wil*_*llk 5 python datetime pandas pandas-groupby
使用 Pandas 日期时间时,我试图按周和年对数据进行分组。但是,我注意到有些年份一年的最后一天与同年的第一周归为一组。
import pandas as pd
day_df = pd.DataFrame(index=pd.date_range('2016-01-01', '2020-12-31'))
for (week, year), subset in day_df.groupby([day_df.index.week, day_df.index.year]):
if week == 1:
print('Week:', subset.index.min(), subset.index.max())
Week: 1 2016-01-04 00:00:00 2016-01-10 00:00:00
Week: 1 2017-01-02 00:00:00 2017-01-08 00:00:00
Week: 1 2018-01-01 00:00:00 2018-12-31 00:00:00
Week: 1 2019-01-01 00:00:00 2019-12-31 00:00:00
Week: 1 2020-01-01 00:00:00 2020-01-05 00:00:00
Run Code Online (Sandbox Code Playgroud)
对于 2018 和 2019 年,一年的第一天与一年的最后一天归为一组!这种行为是预期的吗?为什么一年的最后一天是第 1 周?
我已经用基本if语句得到了我想要的结果,但这种week行为似乎可能会导致问题,因为它是出乎意料的。
这符合我对分组的意图:
for (week, year), subset in day_df.groupby([day_df.index.week, day_df.index.year]):
# Prevent first week of year from including final days of same year
if set(subset.index.month.unique()) == set([1, 12]):
subset = subset.loc[subset.index.month == 1]
if week == 1:
print('Week:', week, subset.index.min(), subset.index.max())
Week: 1 2016-01-04 00:00:00 2016-01-10 00:00:00
Week: 1 2017-01-02 00:00:00 2017-01-08 00:00:00
Week: 1 2018-01-01 00:00:00 2018-01-07 00:00:00
Week: 1 2019-01-01 00:00:00 2019-01-06 00:00:00
Week: 1 2020-01-01 00:00:00 2020-01-05 00:00:00
Run Code Online (Sandbox Code Playgroud)
答案在于 .week() 是一个星期的序号。.week() 方法在文档中最低限度地定义为:
一年中的第几周
周序数正式称为 ISO 周日期。可以 在 python 3.7.3 datetime 文档中的date.isocalendar()下找到有关它在 python 中的更多说明。有关周序如何工作的一般说明,您可以在ISO 周日期的维基百科中找到完整的详细信息。
2019 年的周序可以在EpochConverter.com上找到,它清楚地显示了一年的第一天是 2018 年 12 月 31 日。
如果我们查看 2019 年的第 1 周,我们可以看到 12 月 31 日是第一天,并从 2019 年的第 1 周开始。因此,这实际上符合您在年初过滤器中包含的标准。
下面我们筛选 2018 年底和 2019 年初,看看 .week 正在做什么。
day_df["ordinal"] = day_df.index.week
day_df["day_of_week"] = day_df.index.weekday
print(day_df.loc["2018-12-28":"2019-01-08"])
ordinal day_of_week
2018-12-28 52 4
2018-12-29 52 5
2018-12-30 52 6
2018-12-31 1 0
2019-01-01 1 1
2019-01-02 1 2
2019-01-03 1 3
2019-01-04 1 4
2019-01-05 1 5
2019-01-06 1 6
2019-01-07 2 0
2019-01-08 2 1
Run Code Online (Sandbox Code Playgroud)
您需要添加一个月的标准,以确保它是在您在上面的问题中发现的一月份。这也有效。
for (week, month, year), subset in day_df.groupby(
[day_df.index.week, day_df.index.month, day_df.index.year]
):
if week == 1 and month == 1:
print("Week:", subset.index.min(), subset.index.max())
Run Code Online (Sandbox Code Playgroud)
如果您希望第一周在同一天开始,请使用[pandas.period.strftime()] 5
%U 定义为
一年中的周数(星期日作为一周的第一天)作为十进制数 [00,53]。新年第一个星期日之前的所有日子都被视为第 0 周。
对于您的数据框,这看起来像:
day_df['date'] = day_df.index
day_df["day_name"] = day_df['date'].dt.day_name()
day_df['str_from_time'] = day_df['date'].apply(lambda x: x.strftime("%U"))
day_df.loc["2018-12-28":"2019-01-08",['ordinal', 'str_from_time', 'day_of_week', 'day_name']]
ordinal str_from_time day_of_week day_name
2018-12-28 52 51 4 Friday
2018-12-29 52 51 5 Saturday
2018-12-30 52 52 6 Sunday
2018-12-31 1 52 0 Monday
2019-01-01 1 00 1 Tuesday
2019-01-02 1 00 2 Wednesday
2019-01-03 1 00 3 Thursday
2019-01-04 1 00 4 Friday
2019-01-05 1 00 5 Saturday
2019-01-06 1 01 6 Sunday
2019-01-07 2 01 0 Monday
2019-01-08 2 01 1 Tuesday
Run Code Online (Sandbox Code Playgroud)