如何在Pandas DataFrame中按周分组且分组不跨越月份?
Pandas实现按周分组且周不跨月的方法
核心思路
要实现周分组不跨月,最直接的方式是先按月份拆分数据,在每个月内部生成周区间,确保每个周的起始和结束都落在同一个月内,再对每个月的周进行分组统计,最后补全无数据周的0值。
具体实现步骤
1. 导入数据并预处理
先将日期列转为datetime类型,确保后续日期操作可用:
import pandas as pd # 示例数据 data = { 'Date': ['2021-01-15', '2021-01-17', '2021-01-19', '2021-02-04'], 'Value': [4, 3, 10, 1] } df = pd.DataFrame(data) # 转换日期格式 df['Date'] = pd.to_datetime(df['Date'])
2. 生成所有不跨月的周区间
编写函数遍历每个月份,生成该月内的所有周区间(周起始按周一计算,若周结束超出当月月底则取月底):
def generate_month_weeks(start_date, end_date): week_intervals = [] current_month_start = start_date.replace(day=1) while current_month_start <= end_date: # 获取当月最后一天 current_month_end = current_month_start + pd.offsets.MonthEnd(0) # 从当月第一天开始生成周区间 week_start = current_month_start while week_start <= current_month_end: week_end = week_start + pd.Timedelta(days=6) # 周结束不能超过当月月底 if week_end > current_month_end: week_end = current_month_end week_intervals.append((week_start, week_end)) # 下一周起始 week_start = week_end + pd.Timedelta(days=1) # 切换到下一个月 current_month_start = current_month_start + pd.offsets.MonthBegin(1) return week_intervals # 生成覆盖所有数据月份的周区间 min_date = df['Date'].min().replace(day=1) max_date = df['Date'].max() + pd.offsets.MonthEnd(0) all_month_weeks = generate_month_weeks(min_date, max_date)
3. 生成周区间对照表
将周区间转为DataFrame,方便后续匹配:
week_df = pd.DataFrame(all_month_weeks, columns=['Week_Start', 'Week_End']) week_df['Week'] = week_df['Week_Start'].dt.strftime('%Y-%m-%d') + '-' + week_df['Week_End'].dt.strftime('%Y-%m-%d')
4. 匹配原数据与周区间并分组求和
给原数据的每条记录匹配对应的周区间,再按周分组计算Value的总和:
# 给每个日期匹配对应的周区间 def match_week(date, week_list): for start, end in week_list: if start <= date <= end: return f"{start.strftime('%Y-%m-%d')}-{end.strftime('%Y-%m-%d')}" return None df['Week'] = df['Date'].apply(lambda x: match_week(x, all_month_weeks)) # 按周分组求和 weekly_sum = df.groupby('Week')['Value'].sum().reset_index()
5. 合并结果并补全空周的0值
将所有周区间与分组结果合并,无数据的周填充0:
final_result = pd.merge(week_df[['Week']], weekly_sum, on='Week', how='left').fillna(0) final_result.rename(columns={'Value': 'Sum_value'}, inplace=True) print(final_result)
输出示例
运行后会得到包含所有月份周区间的结果,例如:
Week Sum_value 0 2021-01-01-2021-01-06 0.0 1 2021-01-07-2021-01-13 0.0 2 2021-01-14-2021-01-20 17.0 3 2021-01-21-2021-01-27 0.0 4 2021-01-28-2021-01-31 0.0 5 2021-02-01-2021-02-07 1.0 ...
自定义调整
- 如果需要以周日作为周结束,只需调整
week_start的初始值为当月第一个周日,或者修改周区间的计算逻辑即可。 - 若不需要显示无数据的周,可跳过合并步骤直接使用
weekly_sum。
内容的提问来源于stack exchange,提问作者bunus19
相关产品推荐
相关产品推荐

