【问题标题】:Pandas rank by multiple columns熊猫按多列排名
【发布时间】:2017-06-17 21:08:35
【问题描述】:

我正在尝试根据两列对熊猫数据框进行排名。 我可以根据一列对其进行排名,但如何根据两列对其进行排名? “SaleCount”,然后是“TotalRevenue”?

import pandas as pd

df = pd.DataFrame({'TotalRevenue':[300,9000,1000,750,500,2000,0,600,50,500],
    'Date':['2016-12-02' for i in range(10)],
    'SaleCount':[10,100,30,35,20,100,0,30,2,20],
    'shops':['S3','S2','S1','S5','S4','S8','S6','S7','S9','S10']})

df['Rank'] = df.SaleCount.rank(method='dense',ascending = False).astype(int)

#df['Rank'] = df.TotalRevenue.rank(method='dense',ascending = False).astype(int)
df.sort_values(['Rank'], inplace=True)

print(df)

当前输出:

    Date        SaleCount   TotalRevenue    shops   Rank
1   2016-12-02  100          9000            S2      1
5   2016-12-06  100          2000            S8      1
3   2016-12-04  35           750             S5      2
2   2016-12-03  30           1000            S1      3
7   2016-12-08  30           600             S7      3
9   2016-12-10  20           500             S10     4
4   2016-12-05  20           500             S4      4
0   2016-12-01  10           300             S3      5
8   2016-12-09  2            50              S9      6
6   2016-12-07  0            0               S6      7

我正在尝试生成这样的输出:

    Date        SaleCount   TotalRevenue    shops   Rank
1   2016-12-02  100          9000            S2      1
5   2016-12-02  100          2000            S8      2
3   2016-12-02  35           750             S5      3
2   2016-12-02  30           1000            S1      4
7   2016-12-02  30           600             S7      5
9   2016-12-02  20           500             S10     6
4   2016-12-02  20           500             S4      6
0   2016-12-02  10           300             S3      7
8   2016-12-02  2            50              S9      8
6   2016-12-02  0            0               S6      9

【问题讨论】:

    标签: python python-3.x pandas rank


    【解决方案1】:

    pd.factorize 将为可迭代的每个唯一元素生成唯一值。我们只需要按照我们想要的顺序排序,然后分解。为了做多列,我们将排序结果转换为元组。

    cols = ['SaleCount', 'TotalRevenue']
    tups = df[cols].sort_values(cols, ascending=False).apply(tuple, 1)
    f, i = pd.factorize(tups)
    factorized = pd.Series(f + 1, tups.index)
    
    df.assign(Rank=factorized)
    
             Date  SaleCount  TotalRevenue shops  Rank
    1  2016-12-02        100          9000    S2     1
    5  2016-12-02        100          2000    S8     2
    3  2016-12-02         35           750    S5     3
    2  2016-12-02         30          1000    S1     4
    7  2016-12-02         30           600    S7     5
    4  2016-12-02         20           500    S4     6
    9  2016-12-02         20           500   S10     6
    0  2016-12-02         10           300    S3     7
    8  2016-12-02          2            50    S9     8
    6  2016-12-02          0             0    S6     9
    

    【讨论】:

      【解决方案2】:

      另一种方法是将两个感兴趣的列类型转换为str,并通过连接它们来组合它们。将它们转换回数值,以便可以根据它们的大小来区分它们。

      method=dense 中,重复值的等级将保持不变。 (这里:6)

      由于您想按降序排列这些,在Series.rank() 中指定ascending=False 可以让您获得所需的结果。

      col1 = df["SaleCount"].astype(str) 
      col2 = df["TotalRevenue"].astype(str)
      df['Rank'] = (col1+col2).astype(int).rank(method='dense', ascending=False).astype(int)
      df.sort_values('Rank')
      

      【讨论】:

      • 是的。否则,rank 将无法根据数量级分配组。
      • @piRSquared:非常感谢 :-)
      • 请注意,将(col1+col2 的两列进行字符串连接会很危险 没有 回退astype(int) 会很危险,因为 '30' > '100' 在字符串土地排序顺序。
      • 这在语法上可能是正确的,但是如果您看到排名仍然有效地基于 TotalRevenue 列。这是因为这两个数字的规模不同,因此它们的总和主要受 TotalRevenue 的影响,而受 SaleCount 的影响不大。也许在加起来之前将它们标准化应该会有所帮助。
      • 这个方案基本上是按照totalrevenue排名的
      【解决方案3】:

      (对两个(非负)int 列进行排名的正确方法是按照 Nickil Maveli 的回答,将它们转换为字符串,将它们连接起来并转换回 int。)

      但是如果您知道TotalRevenue 被限制在某个范围内,这里有一个快捷方式,例如0 到 MAX_REVENUE=100,000 ;直接将它们作为非负整数操作:

      df['Rank'] = (df['SaleCount']*MAX_REVENUE + df['TotalRevenue']).rank(method='dense', ascending=False).astype(int)
      
      df.sort_values('Rank2')
      

      【讨论】:

        【解决方案4】:

        执行此操作的通用方法是将所需的字段分组到一个元组中,无论类型如何。

        df["Rank"] = df[["SaleCount","TotalRevenue"]].apply(tuple,axis=1)\
                     .rank(method='dense',ascending=False).astype(int)
        
        df.sort_values("Rank")
        
           TotalRevenue        Date  SaleCount shops  Rank
        1          9000  2016-12-02        100    S2     1
        5          2000  2016-12-02        100    S8     2
        3           750  2016-12-02         35    S5     3
        2          1000  2016-12-02         30    S1     4
        7           600  2016-12-02         30    S7     5
        4           500  2016-12-02         20    S4     6
        9           500  2016-12-02         20   S10     6
        0           300  2016-12-02         10    S3     7
        8            50  2016-12-02          2    S9     8
        6             0  2016-12-02          0    S6     9
        

        【讨论】:

        • 如果我们想在这种情况下按另一列(如商店)进行分组怎么办?
        • @EduardoEPF 将其添加到列表中,即 df[["SaleCount","TotalRevenue", "shops"]].apply(tuple,axis=1)\.rank(method='dense ',ascending=False).astype(int)
        【解决方案5】:

        sort_values + GroupBy.ngroup

        这将给出dense 排名。

        应该在 groupby 之前按所需的顺序对列进行排序。在 groupby 中指定 sort=False 会遵循这种排序,以便按照它们在排序后的 DataFrame 中出现的顺序对组进行标记。

        cols = ['SaleCount', 'TotalRevenue']
        df['Rank'] = df.sort_values(cols, ascending=False).groupby(cols, sort=False).ngroup() + 1
        

        输出:

        print(df.sort_values('Rank'))
        
           TotalRevenue        Date  SaleCount shops  Rank
        1          9000  2016-12-02        100    S2     1
        5          2000  2016-12-02        100    S8     2
        3           750  2016-12-02         35    S5     3
        2          1000  2016-12-02         30    S1     4
        7           600  2016-12-02         30    S7     5
        4           500  2016-12-02         20    S4     6
        9           500  2016-12-02         20   S10     6
        0           300  2016-12-02         10    S3     7
        8            50  2016-12-02          2    S9     8
        6             0  2016-12-02          0    S6     9
        

        【讨论】:

          猜你喜欢
          • 2017-05-23
          • 2021-05-13
          • 2016-11-19
          • 2019-02-14
          • 2022-11-21
          • 1970-01-01
          • 2013-12-20
          • 1970-01-01
          相关资源
          最近更新 更多