【问题标题】:using pandas to create new columns based on intra-group rank-order使用 pandas 根据组内排名创建新列
【发布时间】:2015-03-24 03:07:08
【问题描述】:

我有一个包含大量行的 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)
})

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

  • 组内亮度排序,使最亮的 组的成员将获得 0 的值,下一个最亮的 1 等。

  • 组中最亮的成员的颜色。因此,对于此列,同一组的所有成员将被分配相同的值,该值等于组内亮度等级 = 0 的成员的“颜色”。

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

【问题讨论】:

    标签: python algorithm numpy pandas aggregation


    【解决方案1】:

    我会再试一次:

    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 值。之后我们将df 与members 结合起来,得到brightness 值最高的成员的color 值。基本上,我们将members 和df 中具有相同brightness 和groupID 值的所有行组合起来。

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

    df 现在看起来如下:

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

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

    我们现在可以合并数据帧members 和df:

    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
    

    【讨论】:

    • 这确实快得多,cel。这绝对解决了“找到每个小组最聪明的成员”的问题。这不是我想要的,它是“找到最亮的组成员的 color,但无论如何这仍然非常有用。如果你不介意的话,我很乐意投票简要解释这种语法背后的逻辑,这比你的第一个解决方案更难理解。(同样,我很乐意对颜色问题给予额外的支持,但你已经很有帮助了)。
    • @aph,还有另一个更新......我猜它变得越来越复杂......:D
    • 我认为使用transform 更干净,但不幸的是我的测试显示它更慢。 :-/ 我认为基本问题是代码库中 Python 与 Cython 的平衡针对有很多成员的少数组进行了优化,而不是很多组。
    • @DSM transform 而不是 aggregate?
    • 是的,自动执行max up 的广播(对于简化的情况,我们只是试图找出一行具有最大组亮度的位置;或者如果我们可以使用idxmax需要保留位置)。但是我按照这些思路尝试的一切都比你的方法慢得多..
    【解决方案2】:

    这是我的玩具示例:

    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
    

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

    【讨论】:

    • 优雅的解决方案;这感觉很自然。您的解决方案也可以完美地扩展到 1e6 个成员,但您说得对,它很慢:当我增加 Num_members 和 Num_groups 时,运行时间为 20 秒。由于组内排序,我需要的操作可能本质上是昂贵的。虽然我用直接 C 语言编写的 FOR 循环执行完全相同的任务比这快大约 10 倍,所以我不确定性能下降的根本原因是什么。
    • 所以沿着这些思路的一个想法是,我可能可以不用每个成员的排名。我真正需要知道的是每个成员是最聪明的还是最不聪明的。所以 .idxmax 可能比全等级排序快很多。知道我将如何使用 idxmax 以及我询问的第二列的自定义函数 - 最亮组成员的颜色吗?
    猜你喜欢
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-26
    • 2021-09-30
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    相关资源
    最近更新 更多