有没有办法编写DataFrame.agg方法中使用的聚合函数,可以访问聚合的多个数据列?典型的用例是加权平均加权标准偏差函数.
我希望能够写出类似的东西
def wAvg(c, w):
return ((c * w).sum() / w.sum())
df = DataFrame(....) # df has columns c and w, i want weighted average
# of c using w as weight.
df.aggregate ({"c": wAvg}) # and somehow tell it to use w column as weights ...
Run Code Online (Sandbox Code Playgroud)
Wes*_*ney 85
是; 使用该.apply(...)函数,该函数将在每个子函数上调用DataFrame.例如:
grouped = df.groupby(keys)
def wavg(group):
d = group['data']
w = group['weights']
return (d * w).sum() / w.sum()
grouped.apply(wavg)
Run Code Online (Sandbox Code Playgroud)
Iya*_*Lin 12
这是一个具有以下优点的解决方案:
:
df.groupby('group')
.apply(lambda x: pd.Series({
'weighted_average': np.average(x.data, weights = x.weights)})
Run Code Online (Sandbox Code Playgroud)
您还可以使用相同的代码来执行多个聚合:
df.groupby('group')
.apply(lambda x: pd.Series({
'weighted_average': np.average(x.data, weights = x.weights),
'regular_average': np.average(x.data)}))
Run Code Online (Sandbox Code Playgroud)
Ted*_*rou 10
可以从 groupby 对象返回任意数量的聚合值apply。简单地,返回一个系列,索引值将成为新的列名。
让我们看一个简单的例子:
df = pd.DataFrame({'group':['a','a','b','b'],
'd1':[5,10,100,30],
'd2':[7,1,3,20],
'weights':[.2,.8, .4, .6]},
columns=['group', 'd1', 'd2', 'weights'])
df
group d1 d2 weights
0 a 5 7 0.2
1 a 10 1 0.8
2 b 100 3 0.4
3 b 30 20 0.6
Run Code Online (Sandbox Code Playgroud)
定义将传递给apply. 它隐式地接受一个 DataFrame - 这意味着data参数是一个 DataFrame。请注意它如何使用多列,这在agggroupby 方法中是不可能的:
def weighted_average(data):
d = {}
d['d1_wa'] = np.average(data['d1'], weights=data['weights'])
d['d2_wa'] = np.average(data['d2'], weights=data['weights'])
return pd.Series(d)
Run Code Online (Sandbox Code Playgroud)
apply使用我们的自定义函数调用 groupby方法:
df.groupby('group').apply(weighted_average)
d1_wa d2_wa
group
a 9.0 2.2
b 58.0 13.2
Run Code Online (Sandbox Code Playgroud)
您可以通过将加权总数预先计算到新的 DataFrame 列中来获得更好的性能,如其他答案中所述,并避免apply完全使用。
我的解决方案与Nathaniel的解决方案类似,只是用于单个列,并且我不会每次都深度复制整个数据帧,这可能会非常慢。解决方案groupby(...)。apply(...)的性能增益约为100x(!)
def weighted_average(df, data_col, weight_col, by_col):
df['_data_times_weight'] = df[data_col] * df[weight_col]
df['_weight_where_notnull'] = df[weight_col] * pd.notnull(df[data_col])
g = df.groupby(by_col)
result = g['_data_times_weight'].sum() / g['_weight_where_notnull'].sum()
del df['_data_times_weight'], df['_weight_where_notnull']
return result
Run Code Online (Sandbox Code Playgroud)
我经常这样做,发现以下内容非常方便:
def weighed_average(grp):
return grp._get_numeric_data().multiply(grp['COUNT'], axis=0).sum()/grp['COUNT'].sum()
df.groupby('SOME_COL').apply(weighed_average)
Run Code Online (Sandbox Code Playgroud)
这将计算 中所有数字列的加权平均值,df并删除非数字列。