将Pandas宽格式DataFrame按滑动3月窗口转换为长格式
解决方法
要实现将宽格式DataFrame转换为每行包含连续3个月数据的滑动长格式,可分两步完成:先将宽表转为基础长表,再通过分组移位拼接连续月份的数据。
步骤1:将宽表转为按月的基础长表
首先用pd.wide_to_long把每个月份的列转成每行对应一个key和一个月份的长表,这是后续处理的基础:
import pandas as pd # 原始数据 data = { 'key':['k1','k2'], 'name_M1':['name', 'name'],'area_M1':[1,2],'length_M1':[11,21],'breadth_M1':[12,22], 'name_M2':['name', 'name'],'area_M2':[1,2],'length_M2':[11,21],'breadth_M2':[12,22], 'name_M3':['name', 'name'],'area_M3':[1,2],'length_M3':[11,21],'breadth_M3':[12,22], 'name_M4':['name', 'name'],'area_M4':[1,2],'length_M4':[11,21],'breadth_M4':[12,22], 'name_M5':['name', 'name'],'area_M5':[1,2],'length_M5':[11,21],'breadth_M5':[12,22], 'name_M6':['name', 'name'],'area_M6':[1,2],'length_M6':[11,21],'breadth_M6':[12,22], } df = pd.DataFrame(data) # 转换为基础长表 df_long = pd.wide_to_long(df, stubnames=['name', 'area', 'length', 'breadth'], i='key', j='month', sep='_', suffix=r'M\d+').reset_index() # 提取月份数字,用于排序和滑动处理 df_long['month_num'] = df_long['month'].str.extract(r'(\d+)').astype(int) df_long = df_long.sort_values(['key', 'month_num']).reset_index(drop=True)
步骤2:分组生成滑动3个月的行
通过分组移位操作,将每个月份的下一个月、下下个月数据拼接为当前行的列,最后过滤掉不完整的行:
# 按key分组,生成第2、3个月的对应列 grouped = df_long.groupby('key') df_long['name_2nd'] = grouped['name'].shift(-1) df_long['area_2nd'] = grouped['area'].shift(-1) df_long['length_2nd'] = grouped['length'].shift(-1) df_long['breadth_2nd'] = grouped['breadth'].shift(-1) df_long['name_3rd'] = grouped['name'].shift(-2) df_long['area_3rd'] = grouped['area'].shift(-2) df_long['length_3rd'] = grouped['length'].shift(-2) df_long['breadth_3rd'] = grouped['breadth'].shift(-2) # 过滤掉没有完整3个月数据的行(最后两行) result = df_long.dropna(subset=['name_3rd']).reset_index(drop=True) # 重命名列并调整顺序 result = result.rename(columns={ 'name': 'name_1st', 'area': 'area_1st', 'length': 'length_1st', 'breadth': 'breadth_1st', 'month': 'start_month' }) final_result = result[[ 'key', 'start_month', 'name_1st', 'area_1st', 'length_1st', 'breadth_1st', 'name_2nd', 'area_2nd', 'length_2nd', 'breadth_2nd', 'name_3rd', 'area_3rd', 'length_3rd', 'breadth_3rd' ]] print(final_result)
原代码失败原因
你之前的pd.wide_to_long用法有误:stubnames参数需要对应宽表中列名的前缀(比如原表中name_M1的前缀是name),而不是直接指定最终要生成的name_1st这类列名。该方法无法直接生成滑动窗口的多行数据,需要先转成基础长表再处理。
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

