如何在Pandas DataFrame中按距每月首次出现偏移行分组?
实现Pandas分组边界的行偏移
场景1:对每个年月组进行内部行偏移(保留原分组结构)
这种方式是在原始的年月分组基础上,每个组跳过前N行(正偏移)或后N行(负偏移),保留调整后的组用于后续处理。
步骤代码
- 确保日期列是datetime类型:
import pandas as pd # 假设日期列名为date df['date'] = pd.to_datetime(df['date'])
- 添加分组标签和组内行序号:
# 生成年月分组标签 df['year_month'] = df['date'].dt.to_period('M') # 计算每个组内的行序号(从0开始计数) df['group_row_idx'] = df.groupby('year_month').cumcount() # 计算每个组的总行数 group_sizes = df.groupby('year_month').size().rename('group_size') df = df.merge(group_sizes, left_on='year_month', right_index=True)
- 根据偏移量筛选行:
# 设置偏移量,正偏移表示跳过每组前N行,负偏移表示跳过每组后N行 offset = 1 # 可替换为-3等其他值 if offset > 0: # 正偏移:保留组内行序号 >= offset的行 filtered_df = df[df['group_row_idx'] >= offset] elif offset < 0: # 负偏移:保留组内行序号 <= (组内总行数-1 - 绝对值偏移量)的行 abs_offset = abs(offset) filtered_df = df[df['group_row_idx'] <= (df['group_size'] - 1 - abs_offset)] else: # 偏移量为0,保留所有行 filtered_df = df.copy()
- 对筛选后的结果进行分组处理:
# 按年月分组做后续聚合操作,比如求和、均值 result = filtered_df.groupby('year_month', as_index=False).agg({'value': 'sum'})
场景2:跨月的偏移分组(调整分组边界为指定行)
如果需要将分组边界设置为每个月的第N行日期,形成跨月的连续分组(比如从1月第2行到2月第2行作为一个组),可以用以下方法:
步骤代码
- 预处理日期列:
df['date'] = pd.to_datetime(df['date']) offset = 1 # 偏移量,正为取每组第N行,负为取每组倒数第N行
- 获取每个月的边界日期:
if offset > 0: # 取每个年月组的第offset行(0开始计数)作为边界 boundary_dates = df.groupby(df['date'].dt.to_period('M')).nth(offset)['date'] elif offset < 0: # 取每个年月组的倒数第abs(offset)行作为边界 abs_offset = abs(offset) boundary_dates = df.groupby(df['date'].dt.to_period('M')).nth(-abs_offset)['date'] else: # 偏移量为0,取每月首日作为边界 boundary_dates = df.groupby(df['date'].dt.to_period('M')).nth(0)['date'] # 排序边界日期,并补充首尾边界确保覆盖所有数据 boundary_dates = boundary_dates.sort_values() boundary_dates = pd.concat([ pd.Series([df['date'].min() - pd.Timedelta(days=1)]), boundary_dates, pd.Series([df['date'].max() + pd.Timedelta(days=1)]) ])
- 生成偏移后的分组标签:
# 用cut将日期分配到对应的区间,right=False表示左闭右开区间 df['offset_group'] = pd.cut( df['date'], bins=boundary_dates, labels=boundary_dates[1:-1], right=False )
- 按新分组进行后续处理:
# 按偏移后的分组做聚合操作 result = df.groupby('offset_group', as_index=False).agg({'value': 'mean'})
验证示例
- 对于日期序列
1/1,1/2,...,2/1,2/2,2/3,偏移量1时,offset_group为1/2的组包含1/2到2/1的所有行;若需要包含2/2,可将right=True,并调整边界日期为下一个月的边界日期。
内容的提问来源于stack exchange,提问作者John Glen
相关产品推荐
相关产品推荐

