Python 如何合并两个表并将行转换为列

Python 如何合并两个表并将行转换为列,python,pandas,dataframe,Python,Pandas,Dataframe,我有两张桌子: T1 id x y 8 42 1.9 9 30 1.9 T2 id signal 8 55 8 56 8 59 9 57 9 58 9 60 目标是获得新的表T3: id x y s1 s2 s3 8 42 1.9 55 56 58 9 30 1.9 57 58 60 如

我有两张桌子:

T1

id  x       y
8   42      1.9
9   30      1.9
T2

id  signal
8   55
8   56  
8   59
9   57
9   58  
9   60
目标是获得新的表T3:

id  x       y       s1      s2      s3
8   42      1.9     55      56      58
9   30      1.9     57      58      60
如果执行此操作,则它只执行合并而不执行转置:

pd.merge(T1, T2, on=['id'])

如何创建列
s1
s2
s3
,每个列对应一行(每个
id
的行数始终固定并等于3)?

更新:

正如@Jeff在他的评论中所写的那样,@ubuntu的解决方案应该比我的更快、更地道:

In [40]: T1.merge(
   ....:     T2.pivot_table(index='id',
   ....:                    values='signal',
   ....:                    columns='s' + T2.groupby(['id'])['signal'].cumcount().astype(str))
   ....:       .reset_index()
   ....: )
Out[40]:
   id   x    y  s0  s1  s2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60
旧答案:

您可以这样做:

In [209]: %paste
(t1.set_index('id')
   .join(t2.groupby('id')['signal']
           .apply(lambda x: x.tolist())
           .apply(pd.Series))
   .reset_index()
)
## -- End pasted text --
Out[209]:
   id   x    y   0   1   2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60
说明:

根据
id
T2
进行分组,并将所有相应的信号“收集”到列表中

In [211]: t2.groupby('id')['signal'].apply(lambda x: x.tolist())
Out[211]:
id
8    [55, 56, 59]
9    [57, 58, 60]
Name: signal, dtype: object
将列表展开为列

In [213]: t2.groupby('id')['signal'].apply(lambda x: x.tolist()).apply(pd.Series)
Out[213]:
     0   1   2
id
8   55  56  59
9   57  58  60
最后通过索引
id

PS如果您想重命名所有数值列,可以这样做(假设您将结果保存到
rslt
DF中):


下面是我使用
groupby
unstack
的方法:

df = df1.merge(df2.groupby('id')['signal'].apply(lambda x: x.reset_index(drop=True)).unstack().reset_index())

df
Out[63]: 
   id   x    y   0   1   2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60
如果我将它们分开:

df2t = df2.groupby('id')['signal'].apply(lambda x: x.reset_index(drop=True)).unstack().reset_index()

df2t
Out[59]: 
   id   0   1   2
0   8  55  56  59
1   9  57  58  60

df = df1.merge(df2t)

df
Out[61]: 
   id   x    y   0   1   2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60
另一种方法是使用//:

屈服

   id   x    y  s0  s1  s2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60

主要技巧是使用
groupby/cumcount
将每组累积计数添加到T2:

In [81]: T2['col'] = 's' + T2.groupby(['id'])['signal'].cumcount().astype(str); T2
Out[81]: 
   id  signal col
0   8      55  s0
1   8      56  s1
2   8      59  s2
3   9      57  s0
4   9      58  s1
5   9      60  s2
然后可以使用
pivot
T2
重塑为(或至少接近)所需的形状:

In [82]: T2 = T2.pivot(index='id', columns='col', values='signal').reset_index(); T2
Out[82]: 
col  id  s0  s1  s2
0     8  55  56  59
1     9  57  58  60
结果
可以通过合并得到:

In [83]: pd.merge(T1, T2)
Out[83]: 
   id   x    y  s0  s1  s2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60

你能简要地评论一下这段代码背后的逻辑吗?@Klue,我已经在我的回答中添加了一个简短的解释-请检查一下仅供参考,像这样使用apply是非惯用和非性能的。使用像@ubuntusoln这样的重塑操作符要好得多。请注意@unutbu的解决方案-它应该比我的更快
In [82]: T2 = T2.pivot(index='id', columns='col', values='signal').reset_index(); T2
Out[82]: 
col  id  s0  s1  s2
0     8  55  56  59
1     9  57  58  60
In [83]: pd.merge(T1, T2)
Out[83]: 
   id   x    y  s0  s1  s2
0   8  42  1.9  55  56  59
1   9  30  1.9  57  58  60