在DataFrame中堆叠两列,重复其他列

3
我有一个类似于这样结构的pandas DataFrame:
df = pd.DataFrame( [
            [ 'foo1', 'a', 'z', 'bar1', 1, 4 ],
            [ 'foo2', 'b', 'y', 'bar2', 2, 5 ],
            [ 'foo3', 'c', 'x', 'bar3', 3, 6 ]
        ] )
df.columns = [ 'foo', 'let1', 'let2', 'bar', 'num1', 'num2' ]
print( df )

    foo let1 let2   bar  num1  num2
0  foo1    a    z  bar1     1     4
1  foo2    b    y  bar2     2     5
2  foo3    c    x  bar3     3     6

我想把列let1let2堆叠起来,并添加一个标签,说明它们来自哪里。对于num1num2也是同样的操作。最终,我希望实现这个效果:
    foo   let letval   bar   num  numval
0  foo1  let1      a  bar1  num1       1
1  foo2  let1      b  bar2  num1       2
2  foo3  let1      c  bar3  num1       3
3  foo1  let2      z  bar1  num2       4
4  foo2  let2      y  bar2  num2       5
5  foo3  let2      x  bar3  num2       6

到目前为止,我已经做了这个:
let = pd.concat( [ df.let1, df.let2 ] )
num = pd.concat( [ df.num1, df.num2 ] )
df = df.drop( ['let1', 'let2', 'num1', 'num2' ], axis=1 )
df = pd.concat( [ df, df ] )    
df[ 'letval' ] = let
df[ 'numval' ] = num
print( df )

    foo   bar letval  numval
0  foo1  bar1      a       1
1  foo2  bar2      b       2
2  foo3  bar3      c       3
0  foo1  bar1      z       4
1  foo2  bar2      y       5
2  foo3  bar3      x       6

然而,我相当确信有一种更简单的方法来实现这一点,而不需要复制虚拟变量和类似的解决方法。
您有什么想法吗?

2
你所完成的部分可以简化为pd.lreshape(df, {'letval': ['let1', 'let2'], 'numval': ['num1', 'num2']})。这不是一个有良好文档的函数,因此将其作为注释添加。 - ayhan
@ayhan,这是一个完美的解决方案 - 把它作为答案。 - MaxU - stand with Ukraine
@MaxU 很不幸,这只是 Luis 已经完成的部分解决方案。它会丢失 let 和 num 指示列。 - ayhan
1
@ayhan @MaxU 是的,我需要列名(或任何标签)作为附加列来进行跟踪...但不知道lreshape,这绝对是一个值得关注的好方法。我也认为将其发布为部分答案是值得的 :) - Luis
@Luis 不回答会增加你得到完整答案的机会,所以最好等一下。 :) - ayhan
3个回答

4

这是我尝试将@ayhan的解决方案与pd.melt()方法相结合的结果:

In [191]: (pd.melt(df.drop(['num1','num2'], 1), id_vars=['foo','bar'],
   .....:          var_name='let', value_name='letval')
   .....:    .assign(numval=pd.lreshape(df.filter(like='num'),
   .....:                               {'numval': ['num1', 'num2']})))
Out[191]:
    foo   bar   let letval  numval
0  foo1  bar1  let1      a       1
1  foo2  bar2  let1      b       2
2  foo3  bar3  let1      c       3
3  foo1  bar1  let2      z       4
4  foo2  bar2  let2      y       5
5  foo3  bar3  let2      x       6

如果我理解正确:您首先只取一个value列,通过删除所有其他列,应用melt,然后再将所有删除的列放回去(reshape+assign)... 我猜测melt只能让您这样做一次,对吗?我的意思是,您只有1个measurementlet)... - Luis
仍在努力理解它。我想我可以喜欢上 melt(以前从未使用过);) - Luis

2
同时,我也想到了一个答案。比@MaxU的回答要谦虚得多,并且基于@ayhan的评论。
let = [ 'let1', 'let2' ]
num = [ 'num1', 'num2' ]

n = df.shape[0]
df = pd.lreshape(df, { 'letval': let, 'numval': num } )

df[ 'let' ] = [ item for item in let for _ in range(n) ]
df[ 'num' ] = [ item for item in num for _ in range(n) ]

print( df )


    bar   foo letval  numval   let   num
0  bar1  foo1      a       1  let1  num1
1  bar2  foo2      b       2  let1  num1
2  bar3  foo3      c       3  let1  num1
3  bar1  foo1      z       4  let2  num2
4  bar2  foo2      y       5  let2  num2
5  bar3  foo3      x       6  let2  num2

1
尝试这个:

dfm =  pd.melt(df.drop(['num1','num2'], 1), id_vars=['foo','bar'], var_name=('let'), value_name=('letval'))
dfm[['num', 'numvals']] = pd.melt(df.drop(['let1','let2'], 1), id_vars=['foo','bar'], var_name=('num'), value_name=('numvals'))[['num', 'numvals']]

dfm:
   foo   bar   let  letval  num  numvals
0  foo1  bar1  let1      a  num1        1
1  foo2  bar2  let1      b  num1        2
2  foo3  bar3  let1      c  num1        3
3  foo1  bar1  let2      z  num2        4
4  foo2  bar2  let2      y  num2        5
5  foo3  bar3  let2      x  num2        6

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