#python #python-3.x #pandas #datetime
#python #python-3.x #pandas #дата и время
Вопрос:
У меня есть данные за пять лет, связанные с финансами. Финансовый год начинается 1 июля и заканчивается 30 июня. Я хочу рассчитать финансовую неделю каждого финансового года. Я хочу применить некоторую операцию к столбцу даты фрейма данных, чтобы, когда я пишу что-то вроде df['date].dt.week
, оно должно возвращать номер финансовой недели вместо номера календарной недели. Поэтому я использовал следующий код для выполнения желаемого результата:
df['date'] = df['date'].apply(pd.Period,freq='W')
df['date'].dt.week
Но это не дало желаемого результата. Может ли кто-нибудь указать мне, где я совершаю ошибку?
Ответ №1:
Я не думаю, что вы можете это сделать pandas
. Тем не менее, вы можете использовать векторизованную функцию, которую я создал ниже business_week
(пока я был на ней, я также создал ее для business day
). Эти функции учитывают високосный год. Эта функция начинает отсчет с первого дня месяца / дня, который вы передаете, а не с определенного дня недели. Пожалуйста, обратите внимание, что в году 52 полных недели и 1 или 2 дополнительных дня в зависимости от високосного года, поэтому 30 июня будет отображаться как неделя 53
, а 29 июня — как високосный год. Вы можете просто заменить 53 на 52, если хотите, чтобы было 52. Вы должны передать следующие параметры:
- Столбец, который вы хотите вывести из рабочей недели в формате datetime
- Начальный месяц
- День начала
Например: df['week'] = business_week(df['date'], 7, 1)
и минимальный воспроизводимый пример ниже:
df = pd.DataFrame({'date':
{0: pd.Timestamp('2019-01-01 00:00:00'),
1: pd.Timestamp('2019-06-28 00:00:00'),
2: pd.Timestamp('2019-06-29 00:00:00'),
3: pd.Timestamp('2019-06-30 00:00:00'),
4: pd.Timestamp('2019-07-01 00:00:00'),
5: pd.Timestamp('2019-07-07 00:00:00'),
6: pd.Timestamp('2019-07-08 00:00:00'),
7: pd.Timestamp('2020-01-01 00:00:00'),
8: pd.Timestamp('2020-06-28 00:00:00'),
9: pd.Timestamp('2020-06-29 00:00:00'),
10: pd.Timestamp('2020-06-30 00:00:00'),
11: pd.Timestamp('2020-07-01 00:00:00'),
12: pd.Timestamp('2020-07-07 00:00:00'),
13: pd.Timestamp('2020-07-08 00:00:00')}})
def business_week(d, start_month, start_day):
from datetime import datetime, timedelta
y_int = d.dt.year
y_str = y_int.astype(str)
start_md = (datetime(2020, start_month, start_day) - timedelta(days=1)).strftime('%m-%d')
start_ymd = pd.to_datetime(y_str '-' start_md)
s = d.dt.dayofyear - start_ymd.dt.dayofyear
m1 = s.mask(s < 1, 365 - abs(s))
m2 = m1.mask((y_int % 4 == 0) amp; (d > start_ymd), m1 - 1)
return np.where(y_int % 4 != 0, (m2 6) / 7, (m2 7) / 7).astype(int)
df['week'] = business_week(df['date'], 7, 1)
df
Out[1]:
date week
0 2019-01-01 27
1 2019-06-28 52
2 2019-06-29 52
3 2019-06-30 53
4 2019-07-01 1
5 2019-07-07 1
6 2019-07-08 2
7 2020-01-01 27
8 2020-06-28 52
9 2020-06-29 53
10 2020-06-30 53
11 2020-07-01 1
12 2020-07-07 1
13 2020-07-08 2
Кроме того, если вы хотите, вы могли бы использовать аналогичный метод для возврата business_day
:
def business_day(d, start_month, start_day):
from datetime import datetime, timedelta
y_int = d.dt.year
y_str = y_int.astype(str)
start_md = (datetime(2020, start_month, start_day) - timedelta(days=1)).strftime('%m-%d')
start_ymd = pd.to_datetime(y_str '-' start_md)
s = d.dt.dayofyear - start_ymd.dt.dayofyear
m1 = s.mask(s < 1, 365 - abs(s))
m2 = m1.mask((y_int % 4 == 0) amp; (d <= start_ymd), m1 1)
return m2
df['day'] = business_day(df['date'], 7, 1)
df
Out[1]:
date day
0 2019-01-01 185
1 2019-06-28 363
2 2019-06-29 364
3 2019-06-30 365
4 2019-07-01 1
5 2019-07-07 7
6 2019-07-08 8
7 2020-01-01 185
8 2020-06-28 364
9 2020-06-29 365
10 2020-06-30 366
11 2020-07-01 1
12 2020-07-07 7
13 2020-07-08 8
Ответ №2:
Series.dt.week
идентификатор устарел. Я не сталкивался с неделей финансового года. Возможно, установить начало номера недели, чтобы оно начиналось с определенной даты.
Обычная неделя года номер я бы попробовал следующее после приведения даты к дате-времени
df.date.apply(lambda x: pd.Period(x,freq='D').week)
или
df['date'].dt.strftime("%W").astype(int)
Комментарии:
1. Я не знал
dt.week
, что он устарел. Похоже,dt.weekofyear
это также устарело: pandas.pydata.org/pandas-docs/stable/reference/api /… . Похоже, сейчас лучший способdt.isocalendar().week
2. @Дэвид Эриксон, отредактирует мой ответ, чтобы удалить его. хороший друг!