Pandas DataFrame 枢轴(重塑?)

Pandas DataFrame pivot (reshape?)

我似乎做错了...这就是我正在尝试做的事情:

import pandas as pd

df = pd.DataFrame({
    'item_id': [1,1,3,3,3],
    'contributor_id': [1,2,1,4,5],
    'contributor_role': ['sing', 'laugh', 'laugh', 'sing', 'sing'],
    'metric_1': [80, 90, 100, 92, 50],
    'metric_2': [180, 190, 200, 192, 150]
})

--->

   item_id contributor_id contributor_role   metric_1  metric_2  
0     1          1             sing              80       180  
1     1          2             laugh             90       190  
2     3          1             laugh             100      200  
3     3          4             sing              92       192  
4     3          5             sing              50       150  

我想将其重塑为:

     item_id        SING_1_contributor_id SING_1_metric_1 SING_1_metric_2  SING_2_contributor_id SING_2_metric_1 SING_2_metric_2 ... LAUGH_1_contributor_id LAUGH_1_metric_1 LAUGH_1_metric_2 ... <LAUGH_2_...>

0       1               1                 80              180                   N/A                N/A              N/A      ...          2                    90           190 ... N/A..

1       3               4                 92              192                   5                  50               150      ...          1                    100          200 ... N/A..

基本上,对于每个 item_id,我想将所有相关数据收集到一行中。每个项目可以有多种类型的贡献者,并且每种类型都有一个最大值(例如,最大 SING 贡献者 = 每个项目 A,最大 LAUGH 贡献者 = 每个项目 B)。每个贡献者都有一组指标(但对于同一贡献者,不同项目/贡献者类型的值可能不同)。

我可能可以通过一些看似低效的方法(例如循环和匹配然后填充模板 df)来实现这一点,但我想知道是否有更有效的方法来实现这一点,可能是通过巧妙地指定 index / values / columns 在枢轴操作中(或任何其他方法..)。

提前感谢您的任何建议!

编辑:

最终将 Ben 的脚本改编成以下内容:

df['role_count'] = df.groupby(['item_id', 'contributor_role']).cumcount().add(1).astype(str)
df['contributor_role'] = df.apply(lambda row: row['contributor_role'] + '_' + row['role_count'], axis=1)
df = df.set_index(['item_id','contributor_role']).unstack()
df.columns = ['_'.join(x) for x in df.columns.values]

您可以使用 cumcount 创建附加密钥,然后执行 unstack

df['newkey']=df.groupby('item_id').cumcount().add(1).astype(str)
df['contributor_id']=df['contributor_id'].astype(str)
s = df.set_index(['item_id','newkey']).unstack().sort_index(level=1,axis=1)
s.columns=s.columns.map('_'.join)
s
Out[38]: 
        contributor_id_1 contributor_role_1  ...  metric_1_3  metric_2_3
item_id                                      ...                        
1                      1               sing  ...         NaN         NaN
3                      1         messaround  ...        50.0       150.0