使用 pandas 根据组内排名顺序创建新列

using pandas to create new columns based on intra-group rank-order

我有一个包含大量行的 pandas DataFrame。我正在尝试根据成员的组内排名顺序为框架创建新列。这是一些假数据,说明了我所拥有的:

Num_members = int(1.e7)
Num_groups = int(1.e5)
members = pd.DataFrame({
    'ID': np.arange(Num_members),
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members),
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members)
})

我正在尝试为成员创建两个新列:

我知道 groupby 操作正是为这种操作而设计的,但我一直无法弄清楚如何正确地执行此操作。速度是一个重要问题,因为我的数据集很大,我需要在 MCMC 似然分析中执行此操作。

这是我的玩具示例:

import pandas as pd
import numpy as np
numpy.random.seed(42)
Num_members = int(10)
Num_groups = int(1)
members = pd.DataFrame({
    'ID': np.arange(Num_members),
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members),
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members)
})

使用计算亮度等级和最大值的自定义函数:

def rank_max_fun(df):
    df["b_rank"] = df.brightness.rank(ascending=False)
    df["b_max"] = df.brightness.max()
    return df

分组和应用

 df = members.groupby("groupID", sort=False).apply(rank_max_fun)

产量:

    ID  brightness  color   groupID groupmass   b_rank  b_max
0   0   8.232334    0.304242    2   0   6   11.329771
1   1   11.464705   0.524756    0   0   2   11.879639
2   2   10.404460   0.431945    2   0   3   11.329771
3   3   10.832290   0.291229    2   0   2   11.329771
4   4   8.082338    0.611853    0   0   3   11.879639
5   5   11.879639   0.139494    0   0   1   11.879639
6   6   11.329771   0.292145    2   0   1   11.329771
7   7   8.849356    0.366362    1   0   1   8.849356
8   8   8.727300    0.456070    2   0   5   11.329771
9   9   8.733618    0.785176    2   0   4   11.329771

缺点:在大型数据集上需要相当长的时间。

我再试一次:

import pandas as pd
import numpy as np
np.random.seed(42)
Num_members = int(10)
Num_groups = int(1)
members = pd.DataFrame({
    'ID': np.arange(Num_members),
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members),
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members)
})

逻辑:

df = members.groupby("groupID").agg({"brightness": np.max})
df = df.reset_index()
df = df.merge(members[["groupID", "brightness", "color"]], on=("groupID", "brightness"))

首先我们进行分组以找到最大值 brightness。之后,我们将 dfmembers 结合起来,得到具有最高 brightness 值的成员的 color 值。基本上,我们合并 membersdf 中的所有行,它们具有与 brightnessgroupID.

相同的值

请注意,如果一个组中有多个值具有最大分数,这可能会导致意外的行重复。

df 现在看起来如下:

    groupID brightness  color
0   0   11.879639   0.139494
1   1   8.849356    0.366362
2   2   11.329771   0.292145

对于每个组,它包含 groupIDbrightness 的最大值和具有最大亮度值的元素的 color

我们现在可以合并数据帧 membersdf:

result = members.merge(df, on="groupID", suffixes=("_member", "_group"))

并得到以下结果:

    ID  brightness_member   color_member    groupID groupmass   brightness_group    color_group
0   0   8.232334    0.304242    2   0   11.329771   0.292145
1   2   10.404460   0.431945    2   0   11.329771   0.292145
2   3   10.832290   0.291229    2   0   11.329771   0.292145
3   6   11.329771   0.292145    2   0   11.329771   0.292145
4   8   8.727300    0.456070    2   0   11.329771   0.292145
5   9   8.733618    0.785176    2   0   11.329771   0.292145
6   1   11.464705   0.524756    0   0   11.879639   0.139494
7   4   8.082338    0.611853    0   0   11.879639   0.139494
8   5   11.879639   0.139494    0   0   11.879639   0.139494
9   7   8.849356    0.366362    1   0   8.849356    0.366362