在循环中更改pandas数据框中的列顺序

3

我有多个pandas.Dataframe对象,想在for循环中重新排列所有对象的列,但无法成功。我的代码如下:

import numpy as np
import pandas as pd

df1 = pd.DataFrame(np.random.rand(5, 5))
df2 = pd.DataFrame(np.random.rand(5, 5))

dfs = [ df1, df2 ]

现在,更改列名称已经生效:

for df in dfs:
    df.columns = [ 'a', 'b', 'c', 'd', 'e' ]

df1.head()

打印(字母列而不是数字列):
          a         b         c         d         e
0  0.276383  0.655995  0.512101  0.793673  0.165763
1  0.841603  0.831268  0.776274  0.670846  0.847065
2  0.626632  0.448145  0.184613  0.763160  0.337947
3  0.502062  0.881765  0.154048  0.908834  0.669257
4  0.254717  0.538606  0.677790  0.088452  0.014447

然而,更改列的顺序并不是以同样的方式进行。以下循环:
for df in dfs:
    df = df[ [ 'e', 'd', 'c', 'b', 'a' ] ]

这将不会改变数据框架。

如果我在循环之外为每个数据框架执行此操作,它可以正常工作:

df1 = df1[ [ 'e', 'd', 'c', 'b', 'a' ] ]
df1.head()

打印以下内容:

          e         d         c         b         a
0  0.165763  0.793673  0.512101  0.655995  0.276383
1  0.847065  0.670846  0.776274  0.831268  0.841603
2  0.337947  0.763160  0.184613  0.448145  0.626632
3  0.669257  0.908834  0.154048  0.881765  0.502062
4  0.014447  0.088452  0.677790  0.538606  0.254717

为什么我不能遍历数据框以更改列的顺序?

我如何遍历列表中的数据框以更改列的顺序?


使用python 3.5.3和pandas 0.23.3。


我觉得这非常有趣。所以基本上你想要迭代dfs列表,然后在调用df1而不是dfs[0]时查看循环中所做的更改,对吗?我非常好奇,为什么在第一个循环中进行修改(即更改列名)会以这种方式工作,但重新排列列却不行。 - pmarcol
@pmarcol 是的,我想在代码后面继续使用 df1 - Luis
看看我的答案就知道了 :) - pmarcol
2个回答

2
使用enumerate函数,记得将其赋值回你的list中:
最初的回答
for i, df in enumerate(dfs):
    dfs[i] = df[['e', 'd', 'c', 'b', 'a']]

这似乎也不会改变原始数据框(df1df2)中的列顺序。 - Luis
不,它不会在原对象上进行“原地”更改。在for循环之后,可能需要使用dfs赋值操作的反向操作——df1, df2 = dfs - Chris Adams
确实,那会起作用。@ChrisA 你介意在你的答案中加入这个吗?我认为它很值得。 - pmarcol

2

我花了一些时间研究这个问题,它实际上给了我一个不错的谜题。
它之所以能够运行,是因为在第一个循环中,您修改了现有对象,但在第二个循环中,您实际上创建了对象并覆盖了旧对象;因此,列表dfs失去了对df1df2的引用。如果您希望代码在第二个循环后将更改应用于df1df2,则只能使用操作原始数据框且不需要覆盖的方法。
我不确定我的方法是否最优,但这就是我的意思:

import numpy as np
import pandas as pd

df1 = pd.DataFrame(np.random.rand(5, 5))
df2 = pd.DataFrame(np.random.rand(5, 5))

dfs = [ df1, df2 ]

for df in dfs:
    df.columns = [ 'a', 'b', 'c', 'd', 'e' ]

for df in dfs:
    for c in ['e', 'd', 'c', 'b', 'a']:
        df.insert(df.shape[1],c+'_new',df[c])
    #df.drop(['e', 'd', 'c', 'b', 'a'], axis=1)
    for c in [ 'a', 'b', 'c', 'd', 'e' ]:
        del df[c]
    df.columns = ['e', 'd', 'c', 'b', 'a']

然后调用df1会打印出:"最初的回答"
           e           d           c           b           a
0   0.550885    0.879557    0.202626    0.218867    0.266057
1   0.344012    0.767083    0.139642    0.685141    0.559385
2   0.271689    0.247322    0.749676    0.903162    0.680389
3   0.643675    0.317681    0.217223    0.776192    0.665542
4   0.480441    0.981850    0.558303    0.780569    0.484447

您关于修改和覆盖对象的解释很好,但最好能找到更好的方法来重新排列列... - Luis
是的,我也希望看到更少的“hackery”方法,但我找不到一种不需要覆盖原始对象的方法。 - pmarcol
如果你遇到了一些 reindex 或类似的问题,请记得回来编辑你的答案 ;) - Luis

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