如何用Pandas从基于主DataFrame均值的副DataFrame填充缺失值?
先理清楚核心需求
主DataFrame里Product为Computer Bundle的行,Percent和Discount字段是空的,需要:
- 用对应
StoreID下所有非缺失Percent的均值填充空的Percent - 再根据
Price和填充后的Percent计算Discount
步骤1:读取并查看原始数据
假设你的df.csv内容是这样的:
StoreID,Product,Price,Percent,Discount
1,Laptop,1000,10,100
1,Mouse,20,5,1
1,Computer Bundle,1200,,
2,Desktop,800,15,120
2,Keyboard,30,7,2.1
2,Computer Bundle,900,,
先读取数据:
import pandas as pd df = pd.read_csv('df.csv') print(df)
步骤2:计算每个StoreID的Percent均值
不用搞复杂的复合索引,直接按StoreID分组求均值就行:
# 按StoreID分组,计算非缺失Percent的均值 store_percent_avg = df.groupby('StoreID')['Percent'].mean().reset_index() # 重命名列方便后续合并 store_percent_avg.columns = ['StoreID', 'Avg_Percent']
步骤3:填充缺失的Percent值
把主表和均值表合并,然后针对性填充Computer Bundle的空值:
# 合并主表和均值表,保留所有行 df = df.merge(store_percent_avg, on='StoreID', how='left') # 只给Product是Computer Bundle的行填充Percent df.loc[df['Product'] == 'Computer Bundle', 'Percent'] = df.loc[df['Product'] == 'Computer Bundle', 'Avg_Percent'] # 删掉临时用的Avg_Percent列 df = df.drop('Avg_Percent', axis=1)
步骤4:计算Discount值
直接用Price * Percent / 100计算,按需保留小数位数:
# 计算Discount,保留两位小数 df['Discount'] = (df['Price'] * df['Percent'] / 100).round(2)
完整代码
import pandas as pd # 读取原始数据 df = pd.read_csv('df.csv') # 计算各StoreID的Percent均值 store_percent_avg = df.groupby('StoreID')['Percent'].mean().reset_index() store_percent_avg.columns = ['StoreID', 'Avg_Percent'] # 合并并填充缺失值 df = df.merge(store_percent_avg, on='StoreID', how='left') df.loc[df['Product'] == 'Computer Bundle', 'Percent'] = df.loc[df['Product'] == 'Computer Bundle', 'Avg_Percent'] df = df.drop('Avg_Percent', axis=1) # 计算Discount df['Discount'] = (df['Price'] * df['Percent'] / 100).round(2) print(df)
预期输出结果
运行后会得到:
StoreID,Product,Price,Percent,Discount
1,Laptop,1000,10.0,100.00
1,Mouse,20,5.0,1.00
1,Computer Bundle,1200,7.5,90.00
2,Desktop,800,15.0,120.00
2,Keyboard,30,7.0,2.10
2,Computer Bundle,900,11.0,99.00
为啥之前复合索引的方法没成功?
你之前用(StoreID, Product)做复合索引,但Computer Bundle的行本身没有有效Percent,分组时会被忽略,导致副DataFrame里根本没有(StoreID, Computer Bundle)的索引项,自然匹配不上。直接按StoreID分组求均值再合并的方式,更直接也更不容易出错。
内容的提问来源于stack exchange,提问作者craig

