【问题标题】:ranks within groupby in pandas在 pandas 的 groupby 中排名
【发布时间】:2014-07-21 11:41:45
【问题描述】:

我有一个典型的“面板数据”(用计量经济学术语来说,不是熊猫面板对象)。数据框有一个Date 列和一个ID 列,以及包含某些值的其他列。对于每个日期,我需要根据 V1 对 ID 进行横截面排名,分成 10 个组(十分位),并创建一个名为 rank_col 的新列(取值 1 到 10)来识别排名。然后汇集所有的 rank1, rank2,...rank10 以获得一些统计数据,例如 mean,std。

这可以通过以下代码在 SAS 中轻松完成,它也说明了我的目的:

proc sort data=df;
    by Date;
proc rank data=df out=df_ranked groups=10;
    var V1;
    ranks rank_col;
    by Date;
run;

df_rankeddf 相同,只是它有更多名为rank_col 的列,其中包含每行所属的排名组。

对不起,我没有示例数据来显示结构,需要一个真正的长数据来说明。但 SAS 代码正是我所追求的。

感谢您的帮助!

【问题讨论】:

    标签: python pandas group-by


    【解决方案1】:

    不需要单独的 foo 可以更简单

    In [782]: df.groupby('Date')['V1'].transform(lambda x: pd.qcut(x, 10, labels=False))
    Out[782]:
    0     6
    1     4
    2     3
    3     8
    4     9
    5     1
    6     0
    7     0
    8     1
    9     7
    10    8
    11    5
    12    2
    13    4
    14    9
    Name: V1, dtype: int64
    

    分配给列

    In [783]: df['ranks'] = df.groupby('Date')['V1'].transform(pd.qcut, 10, labels=False)
    
    In [784]: df
    Out[784]:
              Date  id  V1  ranks
    0   2013-01-01   1  10      6
    1   2013-01-01   2   8      4
    2   2013-01-01   3   6      3
    3   2013-01-01   4  11      8
    4   2013-01-01   5  13      9
    5   2013-01-01   6   4      1
    6   2013-01-01   7   2      0
    7   2013-02-01   1   1      0
    8   2013-02-01   2   3      1
    9   2013-02-01   3   9      7
    10  2013-02-01   4  11      8
    11  2013-02-01   5   7      5
    12  2013-02-01   6   4      2
    13  2013-02-01   7   6      4
    14  2013-02-01   8  14      9
    

    详情

    In [786]: df
    Out[786]:
              Date  id  V1
    0   2013-01-01   1  10
    1   2013-01-01   2   8
    2   2013-01-01   3   6
    3   2013-01-01   4  11
    4   2013-01-01   5  13
    5   2013-01-01   6   4
    6   2013-01-01   7   2
    7   2013-02-01   1   1
    8   2013-02-01   2   3
    9   2013-02-01   3   9
    10  2013-02-01   4  11
    11  2013-02-01   5   7
    12  2013-02-01   6   4
    13  2013-02-01   7   6
    14  2013-02-01   8  14
    

    【讨论】:

    • 这也快了
    【解决方案2】:

    我刚刚发现的一种方法:

    def grouping(data):
        dec=pd.qcut(data['V1'],10,labels=False)
        data['ranks']=dec
        return data
    df_ranked=df.groupby('Date').apply(grouping)
    

    这假定dec 为每一行保留正确的位置。

    如果您有更好的方法,请发表,或指出此方法中的任何错误。

    谢谢!

    编辑:如果您执行以下操作,则可以只返回一个新的 ranks 列:

    >>> df
    
    
             Date  id  V1
    0  2013-01-01   1  10
    1  2013-01-01   2   8
    2  2013-01-01   3   6
    3  2013-01-01   4  11
    4  2013-01-01   5  13
    5  2013-01-01   6   4
    6  2013-01-01   7   2
    7  2013-02-01   1   1
    8  2013-02-01   2   3
    9  2013-02-01   3   9
    10 2013-02-01   4  11
    11 2013-02-01   5   7
    12 2013-02-01   6   4
    13 2013-02-01   7   6
    14 2013-02-01   8  14
    
    >>> foo = lambda x: pd.Series(pd.qcut(x,10,labels=False),index=x.index)
    >>> df['ranks'] = df.groupby('Date')['V1'].apply(foo)
    >>> df
    
             Date  id  V1  ranks
    0  2013-01-01   1  10      6
    1  2013-01-01   2   8      4
    2  2013-01-01   3   6      3
    3  2013-01-01   4  11      8
    4  2013-01-01   5  13      9
    5  2013-01-01   6   4      1
    6  2013-01-01   7   2      0
    7  2013-02-01   1   1      0
    8  2013-02-01   2   3      1
    9  2013-02-01   3   9      7
    10 2013-02-01   4  11      8
    11 2013-02-01   5   7      5
    12 2013-02-01   6   4      2
    13 2013-02-01   7   6      4
    14 2013-02-01   8  14      9
    

    【讨论】:

    • 这是一种合理的做法。您可以稍微更改应用以仅返回 ranks 系列。这将允许您将新的ranks 列分配给原始数据框作为groupby/apply 的结果。但是你的方法很好用。
    • @KarlD。感谢您的配合。我刚刚发现,如果我可以先根据 groupby 变量对数据帧进行排序,那么 groupby 操作会快得多。
    • @KarlD。我试图只返回排名系列dec,groupby 会将整个系列附加到每个行列(单元格)
    • 如果您不介意,我可以添加一个版本,只为您的答案返回一列?
    • @KarlD。干净多了!
    猜你喜欢
    • 2019-02-06
    • 2021-02-21
    • 2018-11-05
    • 1970-01-01
    • 2015-03-06
    • 2017-05-10
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    相关资源
    最近更新 更多