如何用处理后的常规DataFrame替换MultiIndex DataFrame的二级索引数据?
客户数据多级索引替换问题
问题背景
我正在编写客户数据处理算法,按用户ID作为一级索引、月份作为二级索引分组,逐用户处理月度时间序列数据。目前代码除最后一步替换外均正常,核心需求是将重采样后的resampleDF完整替换到原多级索引DataFrametempDF1的对应用户位置,包括索引和所有列数据。
当前代码
import pandas as pd from math import log tempDF1 = pd.read_csv('data.csv', index_col=[0,1], parse_dates=[1], thousands=',') tempDF1["Average"] = 0 tempDF1["Score"] = 0 for id, df in tempDF1.groupby(level=0): for date in df.loc[id].index: df.loc[(id,date),"Average"] = df.loc[(id,date)].Purchased/df.loc[(id,date)].Count df.loc[(id,date),"Score"] = df.loc[(id,date)].Count/10*log(df.loc[(id,date)].Average, 10) try: list(df.loc[(id,"2021-01-01",),:]) except: df.loc[(id, "2021-01-01",),:] = 0 try: list(df.loc[(id,"2023-06-01",),:]) except: df.loc[(id, "2023-06-01",),:] = 0 resampleDF = df.loc[id].resample('M', closed="left").mean().fillna(0) print(resampleDF) tempDF1.loc[id].replace(resampleDF, inplace=True) print(tempDF1)
问题原因
当前tempDF1.loc[id].replace(resampleDF, inplace=True)无法完成预期替换,主要问题:
replace是按值匹配替换,不是按索引覆盖,无法对应重采样后的新索引;- 重采样后的
resampleDF是月末日期索引(如2021-06-30),原数据是月初日期(如2021-06-01),索引不匹配; - 原
tempDF1仅包含用户部分月份数据,resampleDF是完整月度序列,直接替换无法新增缺失行。
解决方案
方法1:构建新结果DataFrame(高效推荐)
import pandas as pd from math import log # 读取初始数据 tempDF1 = pd.read_csv('data.csv', index_col=[0,1], parse_dates=[1], thousands=',') tempDF1["Average"] = 0 tempDF1["Score"] = 0 # 初始化空结果容器 result_df = pd.DataFrame() for user_id, df in tempDF1.groupby(level=0): # 计算Average和Score for date in df.index.get_level_values(1): avg = df.loc[(user_id, date), "Purchased"] / df.loc[(user_id, date), "Count"] df.loc[(user_id, date), "Average"] = avg # 避免log(0)报错 df.loc[(user_id, date), "Score"] = (df.loc[(user_id, date), "Count"] / 10) * log(avg, 10) if avg > 0 else 0 # 补全首尾月份(若不存在) start_date = pd.to_datetime("2021-01-01") end_date = pd.to_datetime("2023-06-01") if start_date not in df.index.get_level_values(1): df.loc[(user_id, start_date), :] = 0 if end_date not in df.index.get_level_values(1): df.loc[(user_id, end_date), :] = 0 # 月度重采样 resampleDF = df.loc[user_id].resample('M', closed="left").mean().fillna(0) # 转换为与原数据匹配的多级索引 resampleDF.index = pd.MultiIndex.from_product( [[user_id], resampleDF.index], names=['user_id', 'Month'] ) # 追加到结果 result_df = pd.concat([result_df, resampleDF]) # 替换原DataFrame tempDF1 = result_df.sort_index() print(tempDF1)
方法2:直接修改原DataFrame
import pandas as pd from math import log tempDF1 = pd.read_csv('data.csv', index_col=[0,1], parse_dates=[1], thousands=',') tempDF1["Average"] = 0 tempDF1["Score"] = 0 for user_id, df in tempDF1.groupby(level=0): # 计算指标 for date in df.index.get_level_values(1): avg = df.loc[(user_id, date), "Purchased"] / df.loc[(user_id, date), "Count"] df.loc[(user_id, date), "Average"] = avg df.loc[(user_id, date), "Score"] = (df.loc[(user_id, date), "Count"] / 10) * log(avg, 10) if avg > 0 else 0 # 补全首尾月份 start_date = pd.to_datetime("2021-01-01") end_date = pd.to_datetime("2023-06-01") if start_date not in df.index.get_level_values(1): df.loc[(user_id, start_date), :] = 0 if end_date not in df.index.get_level_values(1): df.loc[(user_id, end_date), :] = 0 # 重采样 resampleDF = df.loc[user_id].resample('M', closed="left").mean().fillna(0) # 构建多级索引 resample_multi = resampleDF.set_index( pd.MultiIndex.from_product( [[user_id], resampleDF.index], names=['user_id', 'Month'] ) ) # 删除原数据中该用户的旧行,追加处理后的新行 tempDF1 = tempDF1.drop(user_id, level=0) tempDF1 = pd.concat([tempDF1, resample_multi]) # 按索引排序 tempDF1 = tempDF1.sort_index() print(tempDF1)
关键说明
- 两种方法核心都是将
resampleDF转换为与原数据一致的多级索引,确保结构匹配; - 方法1通过新容器拼接避免多次修改原数据,性能更优,适合大数据量场景;
- 新增了
Average>0的判断,避免log(0)引发的数学异常。
内容的提问来源于stack exchange,提问作者Adalast
相关产品推荐
相关产品推荐

