如何创建一个数据透视表 table 索引在一个包含重复条目的列上,这些条目应该按另一列的值进行分组?

How can I create a pivot table indexed on a column with duplicate entries that should be grouped by values of another column?

假设我有一个这样的数据框

import pandas as pd
df = pd.DataFrame({'key1': ['id1','id1','id1','id1','id2','id2','id2','id3'],
                       'key2': ['MIN','MIN','MAX','MAX','MIN','MIN','MAX','MIN'],
                       'key3': [0,1,0,1,0,2,1,0],
                       'value': [-1,-2,11,12,-4,0,9,-2]})

print(df)
  key1 key2  key3  value
0  id1  MIN     0     -1
1  id1  MIN     1     -2
2  id1  MAX     0     11
3  id1  MAX     1     12
4  id2  MIN     0     -4
5  id2  MIN     2      0
6  id2  MAX     1      9
7  id3  MIN     0     -2

考虑到:

我想创建一个枢轴 table 其中:

所以,对于给定的输入,输出应该是

      MIN  MAX 
id1    -2   12     
id2    -4    9
id3    -2  NaN

如果我尝试在数据帧上使用 pivot 函数,我会得到一个 ValueError 因为 key1 有重复值

df.pivot(index='key1', columns='key2', values='value')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-19-eee9e613bc28> in <module>
----> 1 df.pivot(index='key1', columns='key2', values='value')
      2 # ValueError: Index contains duplicate entries, cannot reshape

而且我不能使用 groupby 函数,因为它会将 MIN 和 MAX 值聚合在一起

print(df.groupby('key1').agg(MIN=('value', 'min'), MAX=('value', 'max')))
      MIN  MAX
key1          
id1    -2   12
id2    -4    9
id3    -2   -2

有没有比创建两个单独的系列(一个用于 MIN 值,一个用于 MAX 值;通常,key2 中的每个不同值都是一个系列)更优雅的解决方案?

min_series=df[df['key2'].eq('MIN')].groupby('key1').min()['value']
max_series=df[df['key2'].eq('MAX')].groupby('key1').max()['value']
print(pd.DataFrame({'MIN':min_series, 'MAX':max_series}))
     MIN   MAX
id1   -2  12.0
id2   -4   9.0
id3   -2   NaN

这是解决问题的一种方法,方法是在 key1key2 上对数据帧进行分组,然后根据 [=] 指定的聚合函数对每个子组聚合列 value 13=]:

d = {k: v.agg(k[1].lower()) for k, v in df.groupby(['key1', 'key2'])['value']}
frame = pd.Series(d).unstack()

>>> frame

      MAX  MIN
id1  12.0 -2.0
id2   9.0 -4.0
id3   NaN -2.0

这是一种方法,使用 set_indexunstack 为 key2 的每个值创建一个列。然后你可以使用 groupby 并在 agg 中为 key2

的每个值定义你想要的
res = (df.set_index('key2', append=True)
         ['value'].unstack()
         .groupby(df['key1'])
         .agg({'MAX':'max', 'MIN':'min'})
      )
print(res)
       MAX  MIN
key1           
id1   12.0 -2.0
id2    9.0 -4.0
id3    NaN -2.0