熊猫按多列排名

问题描述 投票:0回答:7

我正在尝试根据两列对 pandas 数据框进行排名。 我可以根据一列对其进行排名,但是如何根据两列对其进行排名呢? “销售计数”,然后是“总收入”?

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
7个回答
28
投票

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

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

13
投票

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

8
投票

另一种方法是将感兴趣的两列类型转换为

str
并通过连接它们来组合它们。将它们转换回数值,以便可以根据其大小来区分它们。

method=dense
中,重复值的排名将保持不变。 (此处:6)

由于您想按降序排列它们,因此在

ascending=False
 中指定 
Series.rank()
可以让您达到所需的结果。

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')


6
投票

sort_values
+
GroupBy.ngroup

这将给出

dense
排名。

列应在分组之前按所需顺序排序。在

sort=False
中指定
groupby
然后遵循此排序,以便按组在排序的 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

1
投票

(对两个(非负)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')

0
投票

此函数将按列列表连续排名,并支持按组排名(如果您仅按多列对所有行进行排序,则无法完成此操作)。

def rank_multicol(
    df: pd.DataFrame,
    rank_by: List[str],
    group_by: Optional[List[str]] = None,
    ascending: Union[List[bool], bool] = True,
    rank_col_name: str = 'rank',
) - > pd.DataFrame:
    df_aux = df.copy()
    columns_to_group_by = [] if group_by is None else group_by
    if type(ascending) is bool:
        ascending = [ascending for _ in range(len(rank_by))]
    elif len(ascending) != len(rank_by):
        raise ValueError("`ascending` must be a scalar or have the same length of `rank_by`.")

    for idx, feature in enumerate(rank_by):
        # TODO: Optimize if no untying is required
        if columns_to_group_by:
            df_to_rank = df_aux.groupby(columns_to_group_by)
        else:
            df_to_rank = df_aux.copy()
        ranks = (
            df_to_rank
            [feature]
            .rank(ascending=ascending[idx], method='min')
            .rename(rank_col_name)
        )
        if rank_col_name in df_aux:
            df_aux[rank_col_name] = ranks + (df_aux[rank_col_name] - 1)
        else:
            df_aux[rank_col_name] = ranks

        columns_to_group_by.append(feature)
    return df_aux

0
投票

如果您使用 groupby,您实际上并没有创建多因素排名,您只是按一个值进行排名并进行子排序。 这不是最优雅的解决方案,但您可以为要排名的每种类型的值创建排名列,聚合并按聚合对它们进行排序。
这显示了排序前的多因素排名。

   TotalRevenue  SaleCount shops  TotRevRnk SaleCntRnk ShopRnk AggRank
1          9000  100        S2     1        1           4        6
5          2000  100        S8     2        1           1        4
3           750  35         S5     4        2           3        9
2          1000  30         S1     3        3           5        11
7           600  30         S7     5        3           2        10

(使用上例中的数据进行比较) 如果对聚合排名进行排序,您可以看到前两项翻转了位置。因此,如果您想要多因素排名,而不仅仅是级联排序,这可能是更好的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.