Pandas:向多级列数据框添加多个列

8
这个问题是为了概括解决此问题提供的解决方案而提出的:Pandas: add a column to a multiindex column dataframe。我需要为每个列索引生成一列。当我们想要添加单个列时,spencerlyon2提供的解决方案有效:df ['bar','three'] = [0,1,2]。但是,我希望将此操作推广到每个一级列索引。源数据框如下:
In [1]: df
Out[2]:
first        bar                 baz
second       one       two       one       two
A      -1.089798  2.053026  0.470218  1.440740
B       0.488875  0.428836  1.413451 -0.683677
C      -0.243064 -0.069446 -0.911166  0.478370

目标DF要求列是其相应索引的列和列的加和。

In [1]: df
Out[2]:
first        bar                           baz                 
second       one       two     three       one       two      three
A      -1.089798  2.053026  0.963228‬  1.440740 -2.317647  -0.876907‬
B       0.488875  0.428836  0.917711 -0.683677  0.345873  -0.337804‬
C      -0.243064 -0.069446 -0.312510  0.478370  0.266761   0.745131‬
2个回答

3

您可以使用具有相同索引的两个数据框架并结合使用join一次性创建一堆列。


首先,使用groupbyaxis=1计算总和。

ndf = df.groupby(df.columns.get_level_values(0), axis=1).sum()

        bar       baz
A  0.963228  1.910958
B  0.917711  0.729774
C -0.312510 -0.432796

(PS:如果您有超过两列,您可以这样做)
df.loc[:, (slice(None), ['one', 'two'])].groupby(df.columns.get_level_values(0), axis=1).sum()

首先,仅切割列'one'和'two',然后再进行groupby操作。

接着,将其与您的列索引匹配,即将其转换为多重索引数据帧,就像您的原始数据帧一样。

ndf.columns = pd.MultiIndex.from_product([ndf.columns, ['three']])

        bar       baz
      three     three
A  0.963228  1.910958
B  0.917711  0.729774
C -0.312510 -0.432796

最后,df.join

finaldf = df.join(ndf).sort_index(axis=1)

如果您真的关心顺序,请使用reindex
finaldf.reindex(['one', 'two', 'three'], axis=1, level=1)

first        bar                           baz                    
second       one       two     three       one       two     three
A      -1.089798  2.053026  0.963228  0.470218  1.440740  1.910958
B       0.488875  0.428836  0.917711  1.413451 -0.683677  0.729774
C      -0.243064 -0.069446 -0.312510 -0.911166  0.478370 -0.432796

感谢rafaelc的回复。不知何故,当我使用df.columns.get_level_values(0)时,在Groupby中出现了ValueError ValueError("Grouper and axis must be same length")。我将其更改为level=0,然后它就可以工作了。有什么想法是什么导致了这个值错误? - SO_tourist
@SO_tourist 你很可能忘记在 groupby 中添加 "axis=1" 作为选项。 - rafaelc

1

我从您的示例输入开始:

first        bar                 baz          
second       one       two       one       two
A      -1.089798  2.053026  0.470218  1.440740
B       0.488875  0.428836  1.413451 -0.683677
C      -0.243064 -0.069446 -0.911166  0.478370

要向每个列MultiIndex的0级别添加新列,您可以运行类似以下内容的代码:
for c1 in df.columns.get_level_values('first').unique():
    # New column int index
    cInd = int(df.columns.get_loc(c1).stop)
    col = (c1, 'three')      # New column name
    newVal = df[(c1, 'one')] + df[(c1, 'two')]
    df.insert(loc=cInd, column=col, value=newVal)  # Insert the new column

在上面的例子中,新列中的值是连续的数字,但在您的情况下,可以根据需要设置它们。
我的代码结果(在列排序后)如下:
first        bar                           baz                    
second       one       two     three       one       two     three
A      -1.089798  2.053026  0.963228  0.470218  1.440740  1.910958
B       0.488875  0.428836  0.917711  1.413451 -0.683677  0.729774
C      -0.243064 -0.069446 -0.312510 -0.911166  0.478370 -0.432796

谢谢您的回复。我稍微修改了我的问题,因为我可能没有表达清楚。我需要每个索引添加一列,并且为了举例说明,新列是onetwo列的相加。 - SO_tourist
我更正了我的答案。现在,在MultiIndex列的顶层为每个名称添加了一个新列。 - Valdi_Bo
结果怎么是对的?OP明确表示three应该是onetwo的总和,哈哈;p - rafaelc
你说得对,我最初漏掉了这个细节。现在新的列包含了总和。 - Valdi_Bo
现在看起来是正确的!但即使这样工作,它也会非常非常非常慢;/ - rafaelc

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