所以我在Pandas DataFrame中有两个值列和两个权重列,并且我想生成第三列,该列按这两列的加权平均值分组。
因此:
df = pd.DataFrame({'category':['a','a','b','b'],
'var1':np.random.randint(0,100,4),
'var2':np.random.randint(0,100,4),
'weights1':np.random.random(4),
'weights2':np.random.random(4)})
df
category var1 var2 weights1 weights2
0 a 84 45 0.955234 0.729862
1 a 49 5 0.225470 0.159662
2 b 77 95 0.957212 0.991960
3 b 27 65 0.491877 0.195680
我想完成:
df
category var1 var2 weights1 weights2 average
0 a 84 45 0.955234 0.729862 67.108023
1 a 49 5 0.225470 0.159662 30.759124
2 b 77 95 0.957212 0.991960 86.160443
3 b 27 65 0.491877 0.195680 37.814851
我已经使用像这样的算术运算符完成了此操作:
df['average'] = df.groupby('category', group_keys=False) \
.apply(lambda g: (g.weights1 * g.var1 + g.weights2 * g.var2) / (g.weights1 + g.weights2))
但是我想将其概括为使用numpy.average,所以我可以例如采用3列或更多列的加权平均值。
我正在尝试类似的方法,但是它似乎不起作用:
df['average'] = df.groupby('category', group_keys=False) \
.apply(lambda g: np.average([g.var1, g.var2], axis=0, weights=[g.weights1, g.weights2]))
返回
TypeError: incompatible index of inserted column with frame index
有人可以帮我吗?
答案 0 :(得分:4)
我什至都不认为您需要{'Place': 'REGION-1', 'Host': 'ABCD', 'INTF': 'fastethernet01/01', 'Last': '0h54m44s', 'Sysid': '01441', 'Speaks': 'IPv4', 'Topologies': 'ipv4-unicast', 'SAPA': 'point-to-point', 'Area': '441', 'IPv4': '1.1.1.1'}
{'Place': 'REGION-1', 'Host': 'EFGH', 'INTF': 'fastethernet01/01', 'Last': '0h54m44s', 'Sysid': '01442', 'Speaks': 'IPv4', 'Topologies': 'ipv4-unicast', 'SAPA': 'point-to-point', 'Area': '442', 'IPv4': '1.1.1.2'}
{'Place': 'REGION-2', 'Host': 'IJKL', 'INTF': 'fastethernet01/01', 'Last': '0h54m44s', 'Sysid': '01443', 'Speaks': 'IPv4', 'Topologies': 'ipv4-unicast', 'SAPA': 'point-to-point', 'Area': '443', 'IPv4': '1.1.1.3'}
。注意,这会将输出与groupby
+ apply
匹配。
尝试一下:
lambda
答案 1 :(得分:0)
由于df中每一行的平均列中都有一个值,因此您实际上不需要分组。您只需要一种动态方法来计算可变数量'varXXX'
列的平均值。
下面的答案依赖于相同数量的'var'列和'weights'列,并具有一致的命名模式,因为它构造了列名字符串
df = pd.DataFrame({'category': ['a', 'a', 'b', 'b'],
'var1': np.random.randint(0, 100, 4),
'var2': np.random.randint(0, 100, 4),
'var3': np.random.randint(0, 100, 4),
'weights1': np.random.random(4),
'weights2': np.random.random(4),
'weights3': np.random.random(4)
})
n_cols = len([1 for i in df.columns if i[:3] == 'var'])
def weighted_av_func(x):
numerator = 0
denominator = 0
for i in range(1, n_cols + 1):
numerator += x['var{}'.format(i)] * x['weights{}'.format(i)]
denominator += x['weights{}'.format(i)]
return numerator / denominator
df['average'] = df.apply(weighted_av_func, axis=1)
print(df)
category var1 var2 var3 weights1 weights2 weights3 average
0 a 53 58 2 0.101798 0.073881 0.919632 10.517238
1 a 52 0 26 0.073988 0.816425 0.888792 15.150578
2 b 30 78 46 0.641875 0.029402 0.370237 37.042735
3 b 36 72 92 0.186941 0.663270 0.774427 77.391136
编辑: 如果要使用np.average,并且可以保证数据帧中var列和weights列的顺序,则可以执行以下操作:
df['np_average'] = df.apply(
lambda x: np.average(a=x[1:1 + n_cols],
weights=x[n_cols + 1:2 * n_cols + 1]),
axis=1)
答案 2 :(得分:0)
这是一种方法:
import numpy as np
import pandas as pd
df = pd.DataFrame({'category': ['a', 'a', 'b', 'b'],
'var1': np.random.randint(0, 100, 4),
'var2': np.random.randint(0, 100, 4),
'weights1': np.random.random(4),
'weights2': np.random.random(4)})
df_averages = df[df.columns.difference(['category', 'var1', 'var2'])]
输出:
weights1 weights2
0 0.002812 0.483088
1 0.159774 0.818346
2 0.285366 0.586706
3 0.427240 0.428667
df_averages['Average'] = df_averages.mean(axis=1)
输出:
weights1 weights2 Average
0 0.002812 0.483088 0.242950
1 0.159774 0.818346 0.489060
2 0.285366 0.586706 0.436036
3 0.427240 0.428667 0.427954
df['Averages'] = df_averages['Average'].astype(float)
输出:
category var1 var2 weights1 weights2 Averages
0 a 60 22 0.002812 0.483088 0.242950
1 a 66 63 0.159774 0.818346 0.489060
2 b 18 10 0.285366 0.586706 0.436036
3 b 68 32 0.427240 0.428667 0.427954
基本上从数据框中删除未加权的列,然后将加权的列移至新列。然后,您可以将平均值应用于该数据框的各行,然后将其合并回去,因为索引将一直相同。