如何按日历周拆分含日期列索引的Pandas DataFrame?
按日历周拆分列索引为日期的Pandas DataFrame
问题描述
现有一个列索引为日期的Pandas DataFrame,需要按周一至周日的日历周拆分为多个子DataFrame。以下是初始化代码及两次尝试的问题:
# Imports import numpy as np # version 1.20.3 import pandas as pd # version 1.3.4 # Dataframe initialization np.random.seed(0) col_idx = pd.date_range(start="2022-12-19", end="2023-01-15", freq="D") data = np.random.rand(5, len(col_idx)) df = pd.DataFrame(data, columns=col_idx)
尝试01的问题
- 2023-01-01被单独拆分为子DataFrame,无法归入2022-12-26至2023-01-01的完整周
- 触发
FutureWarning,提示week访问器已被弃用(Pandas 1.3.4版本)
尝试02的问题
使用pd.Grouper(freq="W-MON", axis=1)分组后,生成的子DataFrame包含28列且行数异常,结果不符合预期
正确实现思路及代码
核心思路
- 使用ISO日历周进行分组:ISO周以周一为起始日、周日为结束日,跨年的周会被归到对应的ISO年份下(例如2023-01-01属于2022年的第52周),完美解决跨年周的拆分问题
- 用
dt.isocalendar()替代弃用的week访问器,获取ISO周的年份和周数,避免警告
代码实现
import numpy as np import pandas as pd # 初始化DataFrame(同原代码) np.random.seed(0) col_idx = pd.date_range(start="2022-12-19", end="2023-01-15", freq="D") data = np.random.rand(5, len(col_idx)) df = pd.DataFrame(data, columns=col_idx) with pd.ExcelWriter("correct_split.xlsx") as writer: row_idx = 1 # 获取列索引的ISO周年份和周数,作为分组键 iso_weeks = df.columns.to_series().apply(lambda x: (x.isocalendar().year, x.isocalendar().week)) # 按ISO周分组(axis=1表示按列分组) grouper = df.groupby(iso_weeks, axis=1) for (week_year, week_num), sub_df in grouper: # 此处可添加子DataFrame的处理逻辑 print(f"处理ISO周:{week_year}年第{week_num}周,包含{len(sub_df.columns)}天") # 写入Excel sub_df.to_excel(writer, startrow=row_idx, index=False) row_idx += len(sub_df) + 3
代码解释
- ISO周分组键:通过
x.isocalendar().year和x.isocalendar().week获取每个日期所属的ISO周年份和周数,确保跨年的日期(如2023-01-01)被归入正确的周组 - 按列分组:
groupby指定axis=1,对列进行分组,得到每个周对应的子DataFrame - Excel写入逻辑:保持原有的行索引累加逻辑,确保每个子DataFrame在Excel中分开显示
另一种实现方式(使用pd.Grouper)
如果偏好使用pd.Grouper,需正确设置频率和周起始日,代码如下:
with pd.ExcelWriter("correct_split_grouper.xlsx") as writer: row_idx = 1 # 设置周频率为"W-SUN"(周日为周结束日,对应周一至周日的周),axis=1表示按列分组 grouper = df.groupby(pd.Grouper(freq="W-SUN", axis=1)) for week_end, sub_df in grouper: # 过滤空的子DataFrame(无对应日期的周) if not sub_df.columns.empty: print(f"处理周:结束于{week_end.date()},包含{len(sub_df.columns)}天") sub_df.to_excel(writer, startrow=row_idx, index=False) row_idx += len(sub_df) + 3
freq="W-SUN"表示以周日为周的结束日,对应周一至周日的完整周- 需过滤空的子DataFrame,因为
pd.Grouper会生成覆盖整个时间范围的所有周,包括无数据的周
内容的提问来源于stack exchange,提问作者Xukrao
相关产品推荐
相关产品推荐

