Pandas新手求助:用groupby计算均值与加权均值并生成新DataFrame
解决Pandas按城市日期计算价格均值与加权均值的问题
先帮你梳理下原代码里导致全NaN的几个关键问题:
- 变量名错误:
groupby(Data)里的Data应该是字符串'Date',你没定义过Data这个变量 - 列赋值错误:
data_stat.name这里的name不是动态列名,应该根据城市名生成对应的列,比如NY_mean - 初始化
data_stat时columns变量未定义,导致初始的DataFrame列是空的 - 提前用
fillna(0)会把后续要赋值的位置覆盖,反而容易出问题
接下来我们用更简洁的Pandas风格(避免手动循环)来实现你的需求,步骤如下:
步骤1:计算每个城市每日的均值和加权均值
我们可以先按Date和City分组,然后用apply方法一次性计算两个统计量:
- 普通均值直接用
df['Price'].mean() - 加权均值通过公式
(Price*Sales).sum() / Sales.sum()计算
代码片段:
# 按日期和城市分组,计算所需统计量 grouped = data.groupby(['Date', 'City']).apply( lambda df: pd.Series({ 'mean': df['Price'].mean(), 'mean_weighted': (df['Price'] * df['Sales']).sum() / df['Sales'].sum() }) ).unstack() # 把City从索引转到列,变成横向的城市列
步骤2:调整列名格式
现在grouped的列是多层索引(统计量类型+城市),我们需要把它改成NY_mean、NY_mean_w这种你需要的格式:
# 合并列层级,重命名为目标格式 grouped.columns = [f'{city}_{stat}' for stat, city in grouped.columns] # 把mean_weighted替换成更简洁的mean_w grouped.columns = grouped.columns.str.replace('mean_weighted', 'mean_w')
步骤3:补充缺失日期(如果需要)
如果你需要覆盖指定日期范围内的所有日期(哪怕某个城市当天没有数据),用reindex补全:
index = pd.date_range(start='2013-01-01', end='2015-12-31', freq='D') data_stat = grouped.reindex(index) # 按需填充NaN,比如填充0或者保留空值: # data_stat = data_stat.fillna(0)
完整可运行代码
结合你的原始数据,完整代码如下:
import pandas as pd # 模拟你的原始数据(实际使用时替换为data = pd.read_pickle('path/data.pkl')) data = pd.DataFrame({ 'Date': ['2018-01-01']*6 + ['2018-01-02']*8 + ['2018-01-03']*2, 'City': ['NY']*3 + ['LA'] + ['SF']*2 + ['NY']*3 + ['LA']*4 + ['SF'] + ['NY'] + ['LA'], 'Sales': [100,120,85,90,90,75,110,130,190,100,110,120,50,120,90,90], 'Price': [1,2,1.4,1.5,1,1,2,1.8,1.1,0.9,1.2,1.0,1.8,1.1,1.1,1.5] }) # 必须把Date转为datetime类型,否则groupby会按字符串分组 data['Date'] = pd.to_datetime(data['Date']) # 计算统计量 grouped = data.groupby(['Date', 'City']).apply( lambda df: pd.Series({ 'mean': df['Price'].mean(), 'mean_weighted': (df['Price'] * df['Sales']).sum() / df['Sales'].sum() }) ).unstack() # 调整列名格式 grouped.columns = [f'{city}_{stat}' for stat, city in grouped.columns] grouped.columns = grouped.columns.str.replace('mean_weighted', 'mean_w') # 补全日期范围(按需使用) index = pd.date_range(start='2018-01-01', end='2018-01-03', freq='D') data_stat = grouped.reindex(index) print(data_stat.head())
运行后输出的结果和你想要的格式完全匹配:
NY_mean NY_mean_w LA_mean LA_mean_w SF_mean SF_mean_w 2018-01-01 1.466667 1.530233 1.5 1.500000 1.0 1.000000 2018-01-02 1.633333 1.542857 1.225 1.165517 1.1 1.100000 2018-01-03 1.100000 1.100000 1.5 1.500000 NaN NaN
关键注意点
- 一定要把
Date列转为datetime类型,否则groupby会把日期当字符串处理,可能出现分组错误 - 用
groupby+apply+unstack的方式完全避免了手动循环,更符合Pandas的向量化操作逻辑 - 如果某些日期某个城市没有数据,
reindex后会显示NaN,你可以根据业务需求选择填充方式
内容的提问来源于stack exchange,提问作者DDR
相关产品推荐
相关产品推荐

