Я создал пользовательскую функцию, которая описывает сезонность, и хочу добавить новый столбец в фрейм данных, применив эту функцию к ряду объектов datetime в фрейме данных pandas. Я пытаюсь создать список, содержащий значения функции date_season, применяемые к датам в фрейме данных.
Все переменные в функции date_season ниже имеют тип datetime.date, за исключением 'dif', который является datetime.timedelta.
Вот функция:
import datetime as dt
import pandas as pd
def date_season(date):
year = date.year
min_season = dt.date(year,1,1)
max_season = dt.date(year,6,30)
dif = abs(max_season - date)
dif_days = dif.days
x = (((max_season - min_season).days) - dif.days * 2) / (max_season - min_season).days
seasonality = np.sin(x * (np.pi) / 2)
return(seasonality)
А вот как создается фрейм данных pandas:
start = dt.date(2017,1,1)
end = dt.date(2019,12,31)
df = pd.DataFrame({'Date': pd.date_range(start, end, freq = "D")})
Попытка создать новый список с параметром сезонности:
z = []
for index, row in df.iterrows():
z.append(date_season(row.Date))
Это возвращает сообщение об ошибке:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-105-63e9cb35ed55> in <module>()
1 z = []
2 for index, row in df.iterrows():
----> 3 z.append(date_season(row.Date))
<ipython-input-71-5e2b35e24e38> in date_season(date)
3 min_season = dt.date(year,1,1)
4 max_season = dt.date(year,6,30)
----> 5 dif = abs(max_season - date)
6 dif_days = dif.days
7 x = (((max_season - min_season).days) - dif.days * 2) / (max_season - min_season).days
pandas\_libs\tslibs\timestamps.pyx in
pandas._libs.tslibs.timestamps._Timestamp.__sub__()
TypeError: descriptor '__sub__' requires a 'datetime.datetime' object but received a 'datetime.date'
Попытка:
new_df = df.apply(lambda x: date_season(x))
возвращается
AttributeError: ("'Series' object has no attribute 'year'", 'occurred at index Date')
Не уверен, почему для этого требуется объект datetime.datetime, потому что функция работает с одиночными входами в формате datetime.date. Есть ли более простой способ перебрать даты и создать новый столбец с результатами этой функции?
Вам нужно определить min_season и max_season как объекты datetime pandas вместо встроенного класса datetime python. Это сбивает с толку, но они не полностью взаимозаменяемы.
def date_season(date):
year = date.year
#use pandas.datetime
min_season = pd.datetime(year,1,1)
max_season = pd.datetime(year,6,30)
dif = abs(max_season - date)
dif_days = dif.days
x = (((max_season - min_season).days) - dif.days * 2) / (max_season - min_season).days
seasonality = np.sin(x * (np.pi) / 2)
return(seasonality)
Теперь вы можете использовать applymap для всего вашего фрейма данных или применить его к одному столбцу.
new_df = df.applymap(date_season)
или
df['Date'].apply(date_season)
Потрясающий! Это работает. Большое спасибо за ответ!
Вызов df.apply применит функцию к каждому столбцу в df. Ваша функция принимает один объект datetime в качестве входных данных. Что вам нужно сделать, так это использовать
df.applymap(date_season)
(если все столбцы являются объектами даты и времени), в противном случае вам нужно применить к одному столбцу, напримерdf['date_column'].apply(date_season)
.