在pandas数据框中反转具有相同名称的多个列

6

I have the following dataframe:

pp  b          pp   b
5   0.001464    6   0.001853
5   0.001459    6   0.001843

有没有一种方法可以将具有相同名称的列转换为多行?
这是所需的输出:
pp  b         
5   0.001464    
5   0.001459    
6   0.001853
6   0.001843
6个回答

10
尝试使用 axis=1 的 groupby
df.groupby(df.columns.values, axis=1).agg(lambda x: x.values.tolist()).sum().apply(pd.Series).T.sort_values('pp')
Out[320]: 
          b   pp
0  0.001464  5.0
2  0.001459  5.0
1  0.001853  6.0
3  0.001843  6.0

使用wide_to_long的有趣方式

s=pd.Series(df.columns)
df.columns=df.columns+s.groupby(s).cumcount().astype(str)

pd.wide_to_long(df.reset_index(),stubnames=['pp','b'],i='index',j='drop',suffix='\d+')
Out[342]: 
            pp         b
index drop              
0     0      5  0.001464
1     0      5  0.001459
0     1      6  0.001853
1     1      6  0.001843

谢谢@Wen,你的解决方案有效。你能告诉我groupby和agg部分是做什么的吗?谢谢! - user308827
1
@user308827,这部分是按列进行分组,对于相同的列,我们将值连接成一个列表,然后只需要展开列表,就可以产生结果。 - BENY

4
这可以使用numpy实现:
res = pd.DataFrame({'pp': df['pp'].values.T.ravel(),
                    'b': df['b'].values.T.ravel()})

print(res)

          b  pp
0  0.001464   5
1  0.001459   5
2  0.001853   6
3  0.001843   6

或者不用明确指定特定的列:

res = pd.DataFrame({i: df[i].values.T.ravel() for i in set(df.columns)})

3
让我们使用melt、cumcount和unstack来处理它们:
dm = df.melt()
dm.set_index(['variable',dm.groupby('variable').cumcount()])\
  .sort_index()['value'].unstack(0)

输出:

variable         b   pp
0         0.001464  5.0
1         0.001459  5.0
2         0.001853  6.0
3         0.001843  6.0

谢谢!我遇到了这个错误:*** TypeError: '<' not supported between instances of 'str' and 'int',目前还不确定是因为示例数据框与我的实际数据框不同还是其他原因。 - user308827

2
我有些惊讶,迄今为止没有人提到使用pd.concat...看下面的例子:

我有些惊讶,迄今为止没有人提到使用pd.concat...看下面的例子:

最初的回答:

df1 = pd.DataFrame({'Col1':[1,2,3,4], 'Col2':[5,6,7,8]})
df1
      Col1  Col2
   0     1     5
   1     2     6
   2     3     7
   3     4     8 

Now if you make:

   df2 = pd.concat([df1,df1])

you get:

   Col1  Col2
0     1     5
1     2     6
2     3     7
3     4     8
0     1     5
1     2     6
2     3     7
3     4     8

这是你想要的,不是吗?最初的回答。

0
如果您提前知道重复次数,使用numpy非常容易:
import numpy as np
import pandas as pd

repetitions=5
rows=2
original_columns=list('ab')

df=pd.DataFrame(np.random.randint(0,10,[rows,len(original_columns)*repetitions]), columns=original_columns*repetitions)
display(df)

    a   b   a   b   a   b   a   b   a   b
0   6   4   7   5   2   5   3   1   4   3
1   1   5   4   9   6   2   9   5   3   6

# now the interesting part:
df=pd.concat(np.hsplit(df, repetitions))
display(df)


    a   b
0   6   4
1   1   5
0   7   5
1   4   9
0   2   5
1   6   2
0   3   1
1   9   5
0   4   3
1   3   6

0

一种选择是使用pivot_longerpyjanitor - 在这种情况下,我们利用了pp后面跟着b的事实 - 我们可以安全地将它们配对并重塑为两列。

# pip install pyjanitor
import pandas as pd
import janitor

arr = ['pp', 'b']
df.pivot_longer(index = None, names_to = arr, names_pattern = arr)
   pp         b
0   5  0.001464
1   5  0.001459
2   6  0.001853
3   6  0.001843

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