Pandas:处理多Sales列DataFrame,转换并合并为月度销售数据
我来帮你搞定这个Pandas数据重塑的需求!结合你给出的输入示例和期望输出,我们可以分三步完成数据转换与合并:
步骤1:清理原始数据,拆分月份映射与业务数据
首先得把原始数据里的月份元数据和实际销售数据分开——从你的示例来看,前几行是列名、月份标记和具体月份,从第5行开始才是真正的业务数据(ID、Desc、销售额)。
import pandas as pd # 读取原始文件(如果是Excel可以替换为pd.read_excel) df = pd.read_csv("your_input_file.csv", header=None) # 提取列名和所有Sales开头的列 col_names = df.iloc[0].tolist() sales_cols = [col for col in col_names if col.startswith("Sales")] # 构建Sales列与月份的映射关系(假设月份在第3行,对应索引2) month_mapping = {} for col in sales_cols: col_index = col_names.index(col) month_mapping[col] = df.iloc[2, col_index] # 提取实际业务数据,用第一行作为列名并重置索引 actual_data = df.iloc[4:].rename(columns=df.iloc[0]).reset_index(drop=True)
步骤2:将宽表转成目标长表格式
接下来用Pandas的melt函数把横向的Sales列转成纵向的SalesMonth和SalesValue,完美适配你的需求:
# 重塑数据:保留ID、Desc,把Sales列转成长表 melted_df = actual_data.melt( id_vars=["ID", "Desc"], # 需要保留的非Sales字段 value_vars=sales_cols, # 要转换的Sales系列列 var_name="Temp_Sales_Col", # 临时存储原Sales列名的字段 value_name="SalesValue" # 销售额字段 ) # 用月份映射替换临时列,得到真正的SalesMonth melted_df["SalesMonth"] = melted_df["Temp_Sales_Col"].map(month_mapping) # 清理临时列,调整字段顺序 melted_df = melted_df.drop(columns=["Temp_Sales_Col"])[["ID", "Desc", "SalesMonth", "SalesValue"]]
这时候melted_df的结构就符合预期了,每个ID的每个月份销售额都会单独成一行,自动保留ID的重复值。
步骤3:与其他数据合并
假设你有包含X、Y字段的其他数据集(比如other_df),直接通过ID列合并即可:
# 示例:假设other_df是你的其他数据 other_df = pd.DataFrame({ "ID": ["1", "2", "3"], "X": ["xxx", "yyy", "zzz"], "Y": ["yyyy", "yyyy", "yyyy"] }) # 左合并保留所有销售数据,按期望顺序调整字段 final_df = pd.merge(melted_df, other_df, on="ID", how="left") final_df = final_df[["X", "Y", "ID", "SalesMonth", "SalesValue"]]
关键细节处理
- 空值处理:如果有
NaN(比如示例中第3行的Sales1),可以用melted_df.dropna(subset=["SalesValue"])删除,或者melted_df.fillna(0)填充为0,按需选择。 - 月份位置调整:如果你的月份信息不在第3行,只需要修改
df.iloc[2, col_index]中的索引值即可。 - 数据类型:如果ID需要转成数值型,用
final_df["ID"] = final_df["ID"].astype(int)即可。
完整运行示例
把上面的代码整合后,运行输出会和你给出的期望示例一致:
X Y ID SalesMonth SalesValue 0 xxx yyyy 1 Jan 10 1 xxx yyyy 1 Feb 20 2 xxx yyyy 1 Mar 30 3 xxx yyyy 1 Jan 11 4 xxx yyyy 1 Feb 21 5 xxx yyyy 1 Mar 31 6 yyy yyyy 2 Jan 7 7 yyy yyyy 2 Feb NaN 8 yyy yyyy 2 Mar 0 9 zzz yyyy 3 Jan 10 10 zzz yyyy 3 Feb 20 11 zzz yyyy 3 Mar 10
内容的提问来源于stack exchange,提问作者user6083088
相关产品推荐
相关产品推荐

