Pandas - 基于多列进行分组和排名

5

I have a dataframe like this:

df = pd.DataFrame({'asset_id': [10,10, 10, 20, 20, 20], 'method_id': ['p2','p3','p4', 'p3', 'p1', 'p2'], 'method_rank': [5, 2, 2, 2, 5, 1], 'conf_score': [0.8, 0.6, 0.8, 0.9, 0.7, 0.5]} , columns= ['asset_id', 'method_id','method_rank', 'conf_score']) 

看起来是这样的:

   asset_id method_id  method_rank  conf_score
0    10        p2          5         0.8
1    10        p3          2         0.6
2    10        p4          2         0.8
3    20        p3          2         0.9
4    20        p1          5         0.7
5    20        p2          1         0.5

我希望按照资产ID对行进行分组,并根据method_rank升序和conf_score降序为每行分配一个总体排名。

即,我希望结果看起来像这样:

  asset_id method_id  method_rank  conf_score  overall_rank
5    20        p2         1           0.5          1.0
3    20        p3         2           0.9          2.0
2    10        p4         2           0.8          1.0
1    10        p3         2           0.6          2.0
0    10        p2         5           0.8          3.0
4    20        p1         5           0.7          3.0

如何在pandas中使用group by和ranking实现这个功能?看起来在pandas中只能基于一列进行操作,例如:

df["overall_rank"] = df.groupby('asset_id')['method_rank'].rank("first")

但我希望实现类似以下的内容。
df["overall_rank"] = df.groupby('asset_id')[['method_rank', 'conf_score']].rank("first", ascending = [True, False])

我该如何做到这一点?我知道一个不太正规的方法是先在整个数据帧上使用sort_values,然后再使用groupby,但是当我只想在每个组中排序几行时,对整个数据帧的行进行排序似乎太昂贵了。

1个回答

10

方法1:

df.sort_values(['asset_id', 'method_rank', 'conf_score'], ascending=[True, True, False], inplace=True)
df['overall_rank'] = 1
df['overall_rank'] = df.groupby(['asset_id'])['overall_rank'].cumsum()

df

   asset_id method_id  method_rank  conf_score  overall_rank
2        10        p4            2         0.8             1
1        10        p3            2         0.6             2
0        10        p2            5         0.8             3
5        20        p2            1         0.5             1
3        20        p3            2         0.9             2
4        20        p1            5         0.7             3

方法2:

定义一个函数来对每个组进行排序:

def handle_group(group):
    group.sort_values(['method_rank', 'conf_score'], ascending=[True, False], inplace=True)
    group['overall_rank'] = np.arange(1, len(group)+1)
    return group

df.groupby('asset_id', as_index=False).apply(handle_group)

性能测试:

def run1(df):
    df = df.sort_values(['asset_id', 'method_rank', 'conf_score'], ascending=[True, True, False])
    df['overall_rank'] = 1
    df['overall_rank'] = df.groupby(['asset_id'])['overall_rank'].cumsum()    
    return df

def handle_group(group):
    group.sort_values(['method_rank', 'conf_score'], ascending=[True, False], inplace=True)
    group['overall_rank'] = np.arange(1, len(group)+1)
    return group

def run2(df):
    df = df.groupby('asset_id', as_index=False).apply(handle_group)
    return df

dfn = pd.concat([df]*10000, ignore_index=True)

%%timeit
df1 = run1(dfn)
# 8.61 ms ± 317 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


%%timeit
df2 = run2(dfn).droplevel(0)
# 31.6 ms ± 404 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

实际上,method1比method2更有效率。 - Ferris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接