#python #pandas
Вопрос:
У меня есть два столбца во фрейме данных Pandas, которые являются датами.
Я хочу вычесть один столбец из другого, и в результате получится разница в количестве дней в виде целого числа.
Беглый взгляд на данные:
df_test.head(10)
Out[20]:
First_Date Second Date
0 2016-02-09 2015-11-19
1 2016-01-06 2015-11-30
2 NaT 2015-12-04
3 2016-01-06 2015-12-08
4 NaT 2015-12-09
5 2016-01-07 2015-12-11
6 NaT 2015-12-12
7 NaT 2015-12-14
8 2016-01-06 2015-12-14
9 NaT 2015-12-15
Я успешно создал новый столбец с разницей:
df_test['Difference'] = df_test['First_Date'].sub(df_test['Second Date'], axis=0)
df_test.head()
Out[22]:
First_Date Second Date Difference
0 2016-02-09 2015-11-19 82 days
1 2016-01-06 2015-11-30 37 days
2 NaT 2015-12-04 NaT
3 2016-01-06 2015-12-08 29 days
4 NaT 2015-12-09 NaT
Однако я не могу получить числовую версию результата:
df_test['Difference'] = df_test[['Difference']].apply(pd.to_numeric)
df_test.head()
Out[25]:
First_Date Second Date Difference
0 2016-02-09 2015-11-19 7.084800e 15
1 2016-01-06 2015-11-30 3.196800e 15
2 NaT 2015-12-04 NaN
3 2016-01-06 2015-12-08 2.505600e 15
4 NaT 2015-12-09 NaN
Ответ №1:
Как насчёт:
df_test['Difference'] = (df_test['First_Date'] - df_test['Second Date']).dt.days
Это вернет разницу, как int
если бы отсутствующих значений не было ( NaT
), и float
если они есть.
У Панд есть богатая документация по функциям временных рядов / дат и временным дельтам
Комментарии:
1. Согласен с @AllenWang. Это лучший ответ.
2. @ Сделайте так, чтобы по крайней мере 3 предположили, что это приемлемый ответ
3. Возможно, это изменилось в последних версиях. Это работает для меня, используя
.days
сейчас, когда.dt.days
выдает ошибку4. Похоже, что это зависит от результирующего значения. Если они представляют собой серию дат-времени, то
.dt
это обязательно. Можете ли вы проверить результаты выражения. Это фрейм данных или серия? Я все еще пытаюсь выяснить, когда требуется dt5. похоже, это работает только в течение нескольких дней, а не недель или лет.
Ответ №2:
Вы можете разделить столбец dtype
timedelta
на np.timedelta64(1, 'D')
, но вывод не int
будет , но float
, потому что NaN
значения:
df_test['Difference'] = df_test['Difference'] / np.timedelta64(1, 'D')
print (df_test)
First_Date Second Date Difference
0 2016-02-09 2015-11-19 82.0
1 2016-01-06 2015-11-30 37.0
2 NaT 2015-12-04 NaN
3 2016-01-06 2015-12-08 29.0
4 NaT 2015-12-09 NaN
5 2016-01-07 2015-12-11 27.0
6 NaT 2015-12-12 NaN
7 NaT 2015-12-14 NaN
8 2016-01-06 2015-12-14 23.0
9 NaT 2015-12-15 NaN
Ответ №3:
Вы можете использовать модуль datetime, чтобы помочь здесь. Кроме того, в качестве примечания, простое вычитание даты должно работать, как показано ниже:
import datetime as dt
import numpy as np
import pandas as pd
#Assume we have df_test:
In [222]: df_test
Out[222]:
first_date second_date
0 2016-01-31 2015-11-19
1 2016-02-29 2015-11-20
2 2016-03-31 2015-11-21
3 2016-04-30 2015-11-22
4 2016-05-31 2015-11-23
5 2016-06-30 2015-11-24
6 NaT 2015-11-25
7 NaT 2015-11-26
8 2016-01-31 2015-11-27
9 NaT 2015-11-28
10 NaT 2015-11-29
11 NaT 2015-11-30
12 2016-04-30 2015-12-01
13 NaT 2015-12-02
14 NaT 2015-12-03
15 2016-04-30 2015-12-04
16 NaT 2015-12-05
17 NaT 2015-12-06
In [223]: df_test['Difference'] = df_test['first_date'] - df_test['second_date']
In [224]: df_test
Out[224]:
first_date second_date Difference
0 2016-01-31 2015-11-19 73 days
1 2016-02-29 2015-11-20 101 days
2 2016-03-31 2015-11-21 131 days
3 2016-04-30 2015-11-22 160 days
4 2016-05-31 2015-11-23 190 days
5 2016-06-30 2015-11-24 219 days
6 NaT 2015-11-25 NaT
7 NaT 2015-11-26 NaT
8 2016-01-31 2015-11-27 65 days
9 NaT 2015-11-28 NaT
10 NaT 2015-11-29 NaT
11 NaT 2015-11-30 NaT
12 2016-04-30 2015-12-01 151 days
13 NaT 2015-12-02 NaT
14 NaT 2015-12-03 NaT
15 2016-04-30 2015-12-04 148 days
16 NaT 2015-12-05 NaT
17 NaT 2015-12-06 NaT
Теперь измените тип на datetime.timedelta, а затем используйте .метод дней для допустимых объектов timedelta.
In [226]: df_test['Diffference'] = df_test['Difference'].astype(dt.timedelta).map(lambda x: np.nan if pd.isnull(x) else x.days)
In [227]: df_test
Out[227]:
first_date second_date Difference Diffference
0 2016-01-31 2015-11-19 73 days 73
1 2016-02-29 2015-11-20 101 days 101
2 2016-03-31 2015-11-21 131 days 131
3 2016-04-30 2015-11-22 160 days 160
4 2016-05-31 2015-11-23 190 days 190
5 2016-06-30 2015-11-24 219 days 219
6 NaT 2015-11-25 NaT NaN
7 NaT 2015-11-26 NaT NaN
8 2016-01-31 2015-11-27 65 days 65
9 NaT 2015-11-28 NaT NaN
10 NaT 2015-11-29 NaT NaN
11 NaT 2015-11-30 NaT NaN
12 2016-04-30 2015-12-01 151 days 151
13 NaT 2015-12-02 NaT NaN
14 NaT 2015-12-03 NaT NaN
15 2016-04-30 2015-12-04 148 days 148
16 NaT 2015-12-05 NaT NaN
17 NaT 2015-12-06 NaT NaN
Надеюсь, это поможет.
Комментарии:
1. Да, это одно из возможных решений, но я думаю, что это не рекомендуемый подход, потому что вывод столбца
Diffference
object
и следующая обработка (добавление, вычитание…) невозможны.2. @jesrael, есть и другие способы, например, ваше решение. Однако добавление/вычитание не является проблемой при использовании NAN, смешанных с типами int в столбце. Они будут автоматически отлиты для операций с плавающей точкой по мере необходимости.
Ответ №4:
Я чувствую, что общий ответ не подходит, если даты «охватывают» около года. Это было бы полезно для понимания близости даты, точной по дням года. Чтобы выполнить эти операции с строками, я сделал следующее. (Я использовал это в бизнес-среде при продлении подписки клиентов).
def get_date_difference(row, x, y):
try:
# Calcuating the smallest date difference between the start and the close date
# There's some tricky logic in here to calculate for determining date difference
# the other way around (Dec -> Jan is 1 month rather than 11)
sub_start_date = int(row[x].strftime('%j')) # day of year (1-366)
close_date = int(row[y].strftime('%j')) # day of year (1-366)
later_date_of_year = max(sub_start_date, close_date)
earlier_date_of_year = min(sub_start_date, close_date)
days_diff = later_date_of_year - earlier_date_of_year
# Calculates the difference going across the next year (December -> Jan)
days_diff_reversed = (365 - later_date_of_year) earlier_date_of_year
return min(days_diff, days_diff_reversed)
except ValueError:
return None
Тогда функция может быть:
dfAC_Renew['date_difference'] = dfAC_Renew.apply(get_date_difference, x = 'customer_since_date', y = 'renewal_date', axis = 1)
Ответ №5:
Создайте векторизованный метод
def calc_xb_minus_xa(df):
time_dict = {
'<Minute>': 'm',
'<Hour>': 'h',
'<Day>': 'D',
'<Week>': 'W',
'<Month>': 'M',
'<Year>': 'Y'
}
time_delta = df.at[df.index[0], 'end_time'] - df.at[df.index[0], 'open_time']
offset_base_name = str(to_offset(time_delta).base)
time_term = time_dict.get(offset_base_name)
result = (df.end_time - df.open_time) / np.timedelta64(1, time_term)
return result
Затем в вашем df сделайте:
df['x'] = calc_xb_minus_xa(df)
Это будет работать в течение минут, часов, дней, недель, месяцев и лет.
open_time и end_time необходимо изменить в соответствии с вашим df