Pandas按每列进行分组并为每个组添加新列

3
我有一个类似这样的数据框:
lvl1=['l1A','l1A','l1B','l1C','l1D']
lvl2=['l2A','l2A','l2A','l26','l27']
wgt=[.2,.3,.15,.05,.3]
lvls=[lvl1,lvl2]
df=pd.DataFrame(wgt, lvls).reset_index()
df.columns = ['lvl' + str(i) for i in range(1,3)] + ['wgt']
df
  lvl1 lvl2   wgt
0  l1A  l2A  0.20
1  l1A  l2A  0.30
2  l1B  l2A  0.15
3  l1C  l26  0.05
4  l1D  l27  0.30

我希望能够在每个层级中获得平均重量,并将其作为单独的列添加到此数据框中。

pd.concat([df, df.groupby('lvl1').transform('mean').add_suffix('_l1avg'), df.groupby('lvl2').transform('mean').add_suffix('_l2avg')], axis=1)
  lvl1 lvl2   wgt  wgt_l1avg  wgt_l2avg
0  l1A  l2A  0.20       0.25   0.216667
1  l1A  l2A  0.30       0.25   0.216667
2  l1B  l2A  0.15       0.15   0.216667
3  l1C  l26  0.05       0.05   0.050000
4  l1D  l27  0.30       0.30   0.300000

水平可以超过两个,因此我想使用变量来做这件事。当数据集变得非常大时,如何以最佳和高效的方式做到这一点?我不一定需要它们在同一个数据框中。在这种情况下,可以只是一个独立的n x m矩阵(2 x 5),它包含平均权重的矩阵。
3个回答

1
使用列表推导式(list comprehension):
cols = ['lvl1','lvl2']
k = ['{}_avg'.format(x) for x in cols]
df = df.join(pd.concat([df.groupby(c)['wgt'].transform('mean') for c in cols], 1, keys=k))
print (df)
  lvl1 lvl2   wgt  lvl1_avg  lvl2_avg
0  l1A  l2A  0.20      0.25  0.216667
1  l1A  l2A  0.30      0.25  0.216667
2  l1B  l2A  0.15      0.15  0.216667
3  l1C  l26  0.05      0.05  0.050000
4  l1D  l27  0.30      0.30  0.300000

1
l=[]
l.append(df)
for x ,y in  enumerate(df.columns[:-1]):
    l.append(df.groupby(y).transform('mean').add_suffix('_{}1avg'.format(x+1)))
pd.concat(l,1)
Out[1328]: 
  lvl1 lvl2   wgt  wgt_11avg  wgt_21avg
0  l1A  l2A  0.20       0.25   0.216667
1  l1A  l2A  0.30       0.25   0.216667
2  l1B  l2A  0.15       0.15   0.216667
3  l1C  l26  0.05       0.05   0.050000
4  l1D  l27  0.30       0.30   0.300000

0
这是一个非pandas的解决方案。从生成的字典中,可以高效地映射到列。
from collections import defaultdict
import pandas as pd

df = pd.DataFrame([['l1A', 'l2A', 0.20],
                   ['l1A', 'l2A', 0.30],
                   ['l1B', 'l2A', 0.15],
                   ['l1C', 'l26', 0.05],
                   ['l1D', 'l27', 0.30]],
                  columns=['lvl1', 'lvl2', 'wgt'])

results = defaultdict(lambda: defaultdict(float))
arr = df.values

for i in range(1, 3):
    for x in sorted(np.unique(arr[:, i-1])):
        results[i][x] = np.mean(arr[np.where(arr[:, i-1]==x)][:, 2])
    df['avg_lvl'+str(i)] = df['lvl'+str(i)].map(results[i])

#   lvl1 lvl2   wgt  avg_lvl1 avg_lvl2
# 0  l1A  l2A  0.20     0.25  0.216667
# 1  l1A  l2A  0.30     0.25  0.216667
# 2  l1B  l2A  0.15     0.15  0.216667
# 3  l1C  l26  0.05     0.05  0.050000
# 4  l1D  l27  0.30     0.30  0.300000

对于这个小型数据集,我看到了以下3个响应的表现:

%timeit pandas1(df)  # wen
# 10 loops, best of 3: 35 ms per loop

%timeit pandas2(df)  # jezrael
# 100 loops, best of 3: 4.54 ms per loop

%timeit numpy1(df)   # jp_data_analysis
# 1000 loops, best of 3: 1.88 ms per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接