在pandas中进行分组和转置

4

Dataframe有

ID  col  col2   col3   col4

1   A    50      S      1
1   A    52      M      4
1   B    45      N      8
1   C    18      S      7

数据框的需求

ID  col  colA   colB   colC   colD   colE   colF

1   A    50     52      S      M       1      4
1   B    45     NULL    N     NULL     8     NULL
1   C    18     NULL    S     NULL     7     NULL

我希望每个唯一的ID+col(按ID和col分组)只有1行。 如果每个ID+col有多个条目(最多可达2个,不再多),则将col2的第一个值放入colA中,第二个值放入colB中,将col3的第一个值放入colC中,第二个值放入colD中,将col4的第一个值放入colE中,第二个值放入colF中。如果每个ID+col只有一个条目,则对于col2,将值放入colA中,colB为空等。

我试图首先创建一个计数器:

df['COUNT'] = df.groupby(['ID','col']).cumcount()+1

从这里开始,我考虑只需添加一列来表明。
if count=1 then df['colA']=df.col2
if count=2 then df['colB']=df.col2

..但这仍将导致与原始df相同数量的行。

3个回答

3
我认为需要使用set_indexunstack来处理:
df['COUNT'] = df.groupby(['ID','col']).cumcount()+1

df = df.set_index(['ID','col', 'COUNT'])['col2'].unstack().add_prefix('col').reset_index()
print (df)
COUNT  ID col  col1  col2
0       1   A  50.0  52.0
1       1   B  45.0   NaN
2       1   C  18.0   NaN

或者:

c = df.groupby(['ID','col']).cumcount()+1

df = df.set_index(['ID','col', c])['col2'].unstack().add_prefix('col').reset_index()
print (df)
   ID col  col1  col2
0   1   A  50.0  52.0
1   1   B  45.0   NaN
2   1   C  18.0   NaN

编辑:

对于多列的解决方案有所不同,因为涉及到在列中使用 MultiIndex

df['COUNT'] = (df.groupby(['ID','col']).cumcount()+1).astype(str)

#remove col2
df = df.set_index(['ID','col', 'COUNT']).unstack()
#flatten Multiindex
df.columns = df.columns.map('_'.join)
df = df.reset_index()
print (df)
   ID col  col2_1  col2_2 col3_1 col3_2  col4_1  col4_2
0   1   A    50.0    52.0      S      M     1.0     4.0
1   1   B    45.0     NaN      N   None     8.0     NaN
2   1   C    18.0     NaN      S   None     7.0     NaN

感谢您的提醒,我已经更新了问题以涵盖更多的使用情况。 - babz
完美!在字符列中的 None 是否被视为 NULL 一样处理? - babz
是的,完全正确。在pandas中也是一样的,例如.fillna(0)可以很好地处理NoneNaNNaT - jezrael

2
您可以使用 groupby 结合 apply(pd.Series) 进行操作。
df.groupby(['ID','col']).col2.apply(list).apply(pd.Series).add_prefix('col').reset_index()
Out[404]: 
   ID col  col0  col1
0   1   A  50.0  52.0
1   1   B  45.0   NaN
2   1   C  18.0   NaN

@babz,你可以尝试使用df.groupby(['ID','col'])。agg(tuple),我认为将元组转换为单列没有任何好处。 - BENY

1

不确定这是否是您要查找的内容,但它呈现了您要查找的相同结果。请注意,我在同一列上使用多个聚合函数,因此使用ravel函数来展平数据框列。

import pandas as pd
import numpy as np

df = pd.DataFrame({'ID':[1,1,1,1], 
                  'Col1':['A','A','B','C'],
                 'Col2':[50,52,45,18]})

df = df.groupby(['ID','Col1']).agg({'Col2':['first','last']})
df.columns = ["_".join(x) for x in df.columns.ravel()]
df = df.reset_index()
df['Col2_last'] = np.where(df.Col2_first == df.Col2_last, float('nan'), df.Col2_last)

print(df)

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