如何将Pandas的分组结果广播到所有行?

5

使用Pandas 1.0.1版本,针对以下演示数据框,我想用在子组 'box' 上计算的weight和price列的中位数值来代替其数值列(不修改原始数据框):

import pandas as pd
import numpy as np

df = pd.DataFrame({'box': ['a100','a100','a100','a200','a200','a300','a300','a300','a300'], 'id_in_box': ['2x', '1x', '3x', '2x', '1x', '3x', '1x', '2x', '4x'], 'weight': [2, 1, 2, 3, 4, 2, 8, 6, 4.5], 'price': [1.5, 3.2, 2.1, 3.3, 1.5, 3.2, 2.1, 3.3, 4.4]})
df
    box id_in_box  weight  price
0  a100        2x     2.0    1.5
1  a100        1x     1.0    3.2
2  a100        3x     2.0    2.1
3  a200        2x     3.0    3.3
4  a200        1x     4.0    1.5
5  a300        3x     2.0    3.2
6  a300        1x     8.0    2.1
7  a300        2x     6.0    3.3
8  a300        4x     4.5    4.4

实际:

df.groupby('box')[['weight', 'price']].transform(lambda x: np.median(x))
   weight  price
0    2.00   2.10
1    2.00   2.10
2    2.00   2.10
3    3.50   2.40
4    3.50   2.40
5    5.25   3.25
6    5.25   3.25
7    5.25   3.25
8    5.25   3.25

期望的结果:

    box id_in_box  weight  price
0  a100        2x     2.00   2.10
1  a100        1x     2.00   2.10
2  a100        3x     2.00   2.10
3  a200        2x     3.50   2.40
4  a200        1x     3.50   2.40
5  a300        3x     5.25   3.25
6  a300        1x     5.25   3.25
7  a300        2x     5.25   3.25
8  a300        4x     5.25   3.25

我该如何以最高效的方式实现这个目标?


1
我不想修改原始数据框。在运行分组操作之前,我需要创建一个副本,然后将结果分配给该副本吗?这是生成此结果的唯一方法吗? - Javide
3个回答

4
new_df = df[df.columns[:2]].merge(
              df.groupby('box', as_index=False)[['weight', 'price']].median(),
              how='left')

结果:

    box id_in_box  weight  price
0  a100        2x    2.00   2.10
1  a100        1x    2.00   2.10
2  a100        3x    2.00   2.10
3  a200        2x    3.50   2.40
4  a200        1x    3.50   2.40
5  a300        3x    5.25   3.25
6  a300        1x    5.25   3.25
7  a300        2x    5.25   3.25
8  a300        4x    5.25   3.25

2

您需要以某种方式组合这两个输出结果(如评论中所提到的)。复制是可行的(正如您所建议的),但需要两行代码:

df_new = df.copy()
df_new[['weight', 'price']] = df_new.groupby('box')[['weight', 'price']].transform(lambda x: np.median(x))

使用连接(join)可以实现不覆盖原始数据框的单行解决方案,但对于大型数据而言效率不高:

df_new = pd.merge(
    left=df[['box', 'id_in_box']],
    right=df.groupby('box')[['weight', 'price']].median(),
    left_on='box',
    right_index=True
)

0

这是一种原始的方法。

gb = df.groupby(['box'])['weight'].transform(lambda x: np.median(x))
gb1 = df.groupby(['box'])['price'].transform(lambda x: np.median(x))

df['weight'] = gb
df['price'] = gb1

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