Pandas:将相同关键字的行分组到一个行中

3
在pandas中,我正在尝试找出如何根据相同的键分组行,并在一行中包含一个组中具有公共特征集合(按id分组),一组不同的特征。
类似于下面这个例子:
id C1 C2 Uk U1 0 x 1 2 3 4 1 y 5 6 7 8 2 x 1 2 9 10 3 y 5 6 3 11
这里的公共特征集合是'C1'和'C2',不同的特征集合是'Uk'和'U1',以'Uk'作为分组的键。
对于此示例,期望的结果是:
id C1 C2 Uk3_U1 Uk7_U1 Uk9_U1 0 x 1 2 4 NaN 10.0 1 y 5 6 11 8.0 NaN
当然,也可以有'U2'列,但由于结果的列数会更多,所以这样做会使示例变得更加复杂。
生成该数据集的代码如下:
pd.DataFrame({'id': ['x', 'y', 'x', 'y'],
              'C1': [1, 5, 1, 5], 'C2': [2, 6, 2, 6],
              'Uk': [3, 7, 9, 3], 'U1': [4, 8, 10, 11]})

谢谢。
3个回答

3

pd.pivot_table

使用pd.pivot_table可以指定indexcolumns

# add string prefix to Uk series
df['Uk'] = 'Uk' + df['Uk'].astype(str)

# pivot data and add suffix to columns
res = pd.pivot_table(df, index=['id', 'C1', 'C2'], columns='Uk')\
        .add_suffix('_U1').reset_index()

# flatten MultiIndex columns
res.columns = [j or i for i, j in res.columns.values]

print(res)

  id  C1  C2  Uk3_U1  Uk7_U1  Uk9_U1
0  x   1   2     4.0     NaN    10.0
1  y   5   6    11.0     8.0     NaN

2

IIUC

df.set_index(['id','C1','C2','Uk']).U1.unstack().add_prefix('Uk').add_suffix('_U1')
Out[223]: 
Uk        Uk3_U1  Uk7_U1  Uk9_U1
id C1 C2                        
x  1  2      4.0     NaN    10.0
y  5  6     11.0     8.0     NaN

为了符合您的预期输出,但不建议使用。
df.set_index(['id','C1','C2','Uk']).U1.unstack().add_prefix('Uk').add_suffix('_U1').reset_index()

更新
newdf=df.set_index(['id','C1','C2','Uk']).unstack()
newdf.columns=newdf.columns.map('Uk{0[1]}_{0[0]}'.format) 
newdf
Out[236]: 
          Uk3_U1  Uk7_U1  Uk9_U1  Uk3_U2  Uk7_U2  Uk9_U2
id C1 C2                                                
x  1  2      4.0     NaN    10.0     4.0     NaN    10.0
y  5  6     11.0     8.0     NaN    11.0     8.0     NaN

同时在末尾加上.reset_index() - Karn Kumar
@pygo 对于重塑问题,我想保留它们的索引,以便将来转换回去。 - BENY
如果我不仅有 U1,还有 U2,...,U100,我该如何扩展它? - Nicolas Scotto Di Perto

1

pivot + join

您可以使用 pivot 并使用 join 与原始数据框进行组合:

new_df = new_df = df.pivot('id','Uk', 'U1')
                    .add_prefix('Uk').add_suffix('_U1').reset_index()

print(new_df)

Uk id Uk3_U1 Uk7_U1 Uk9_U1
0   x   4.0   NaN    10.0
1   y  11.0   8.0    NaN

new_df.join(df.loc[:,'C1':'C2'])

   id   Uk3  Uk7   Uk9  C1  C2
0  x   4.0  NaN  10.0   1   2
1  y  11.0  8.0   NaN   5   6

如果您想为多个列[C1...Cn]进行数据透视,可以按照以下步骤操作。例如,假设您有以下数据框:

  id  C1  C2  Uk  U1  U2
0  x   1   2   3   4   5
1  y   5   6   7   8   2
2  x   1   2   9  10  10
3  y   5   6   3  11  11

你可以这样做:

values_to_pivot = df.columns.difference(['id', 'C1', 'C2', 'Uk'])
new_df = df.pivot('id','Uk', values_to_pivot).reset_index()
print(new_df)

    id    U1               U2           
Uk        3    7     9     3    7     9
0   x   4.0  NaN  10.0   5.0  NaN  10.0
1   y  11.0  8.0   NaN  11.0  2.0   NaN

new_df.join(df.loc[:,'C1':'C2'])

    (id, )  (U1, 3)  (U1, 7)  (U1, 9)  (U2, 3)  (U2, 7)  (U2, 9)  C1  C2
0      x      4.0      NaN     10.0      5.0      NaN     10.0    1   2
1      y     11.0      8.0      NaN     11.0      2.0      NaN    5   6

我刚刚添加了如何做,@NicolasScottoDiPerto - yatu
好的@NicolasScottoDiPerto,是的 :). 您可以使用df.columns.difference(['id', 'C1', 'C2', 'Uk'])来实现,这将给您一个除了这些列以外的所有列的列表。 - yatu
1
谢谢,这正是我所需要的! - Nicolas Scotto Di Perto
你们的建议和第三个有什么区别? 我现在不确定哪一个是最好的... - Nicolas Scotto Di Perto
让我们在聊天中继续这个讨论 - Nicolas Scotto Di Perto
显示剩余4条评论

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