如何更改DataFrame列的顺序?

1606

我有以下的DataFramedf):

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.rand(10, 5))

我通过赋值来添加更多列:

df['mean'] = df.mean(1)

如何将列 mean 移动到最前面,即将其设置为第一列,同时不改变其他列的顺序?


3
可能是重复的问题Python Pandas - 根据列名重新排列数据框中的列 - Laurence
2
对于基于NumPy的通用解决方案,请参见如何在pandas数据框中移动列,仅假定存在一列级别,即没有MultiIndex - jpp
1
经过足够的搜索,我找到了这个最好的链接,可以用相当简单的术语重新排列多个逻辑的列 [pandas的列重新排列逻辑] [http://www.datasciencemadesimple.com/re-arrange-or-re-order-the-column-of-dataframe-in-pandas-python-2] - ravibeli
1
最终的目标是:df = df[新排列的列名列表] ;D - starriet
1
对于2022年,@WesMckinney的回答比排名第一的回答更为最新。 - PeJota
41个回答

1378

一种简单的方法是使用一个列的列表重新分配数据框,根据需要重新排列。

这是你现在拥有的:

In [6]: df
Out[6]:
          0         1         2         3         4      mean
0  0.445598  0.173835  0.343415  0.682252  0.582616  0.445543
1  0.881592  0.696942  0.702232  0.696724  0.373551  0.670208
2  0.662527  0.955193  0.131016  0.609548  0.804694  0.632596
3  0.260919  0.783467  0.593433  0.033426  0.512019  0.436653
4  0.131842  0.799367  0.182828  0.683330  0.019485  0.363371
5  0.498784  0.873495  0.383811  0.699289  0.480447  0.587165
6  0.388771  0.395757  0.745237  0.628406  0.784473  0.588529
7  0.147986  0.459451  0.310961  0.706435  0.100914  0.345149
8  0.394947  0.863494  0.585030  0.565944  0.356561  0.553195
9  0.689260  0.865243  0.136481  0.386582  0.730399  0.561593

In [7]: cols = df.columns.tolist()

In [8]: cols
Out[8]: [0L, 1L, 2L, 3L, 4L, 'mean']

您可以随意重新排列cols。这就是我将最后一个元素移动到第一位的方法:

In [12]: cols = cols[-1:] + cols[:-1]

In [13]: cols
Out[13]: ['mean', 0L, 1L, 2L, 3L, 4L]

然后按照以下方式重新排序数据框:

In [16]: df = df[cols]  #    OR    df = df.ix[:, cols]

In [17]: df
Out[17]:
       mean         0         1         2         3         4
0  0.445543  0.445598  0.173835  0.343415  0.682252  0.582616
1  0.670208  0.881592  0.696942  0.702232  0.696724  0.373551
2  0.632596  0.662527  0.955193  0.131016  0.609548  0.804694
3  0.436653  0.260919  0.783467  0.593433  0.033426  0.512019
4  0.363371  0.131842  0.799367  0.182828  0.683330  0.019485
5  0.587165  0.498784  0.873495  0.383811  0.699289  0.480447
6  0.588529  0.388771  0.395757  0.745237  0.628406  0.784473
7  0.345149  0.147986  0.459451  0.310961  0.706435  0.100914
8  0.553195  0.394947  0.863494  0.585030  0.565944  0.356561
9  0.561593  0.689260  0.865243  0.136481  0.386582  0.730399

43
如果出现“无法连接'str'和'list'对象”的情况,请确保在cols中对str值进行[]操作: cols = [cols[7]] + cols[:7] + cols[8:]。 - moeabdol
4
@FooBar 这不是集合的并运算,而是两个有序列表的连接。 - Aman
3
我只是想指出你的代码已过时。你对帖子的处理取决于你自己。 - FooBar
2
@FooBar,cols的类型是list,它甚至允许重复(在使用数据框时会被丢弃)。你可能想要使用Index对象。 - alexis
20
这意味着复制所有数据,这非常低效。我希望 pandas 有一种方法可以在不创建副本的情况下完成此操作。 - Konstantin
显示剩余2条评论

854

你也可以像这样做:

df = df[['mean', '0', '1', '2', '3']]

你可以使用以下方式获取列的列表:

cols = list(df.columns.values)

输出结果将是:

['0', '1', '2', '3', 'mean']

在将其放入第一个函数之前,可以轻松地手动重新排列。


10
你可以使用list(df.columns)获取列名列表。 - Jim
33
或者 df.columns.tolist() - Jim
对于像我这样的新手,重新排列从cols获得的列表。然后 df = df [cols],即重新排列的列表被插入到第一个表达式中,而不仅仅是一个括号。 - Sid
7
我认为这不是一个好的答案,因为它没有提供如何更改任何数据框列顺序的代码。比如我使用pd.read_csv()将CSV文件导入为Pandas pd,那么你的答案如何用于更改列顺序呢? - Robvh
7
@Robvh,第二行代码解释如何获取现有列名。从那里,您可以将输出复制到第一行代码中,并按需重新排列。唯一需要知道的其他信息是,如果没有标题,则默认列名为整数而不是字符串。 - daniel brandstetter
显示剩余2条评论

411

只需按照您想要的顺序分配列名:

In [39]: df
Out[39]: 
          0         1         2         3         4  mean
0  0.172742  0.915661  0.043387  0.712833  0.190717     1
1  0.128186  0.424771  0.590779  0.771080  0.617472     1
2  0.125709  0.085894  0.989798  0.829491  0.155563     1
3  0.742578  0.104061  0.299708  0.616751  0.951802     1
4  0.721118  0.528156  0.421360  0.105886  0.322311     1
5  0.900878  0.082047  0.224656  0.195162  0.736652     1
6  0.897832  0.558108  0.318016  0.586563  0.507564     1
7  0.027178  0.375183  0.930248  0.921786  0.337060     1
8  0.763028  0.182905  0.931756  0.110675  0.423398     1
9  0.848996  0.310562  0.140873  0.304561  0.417808     1

In [40]: df = df[['mean', 4,3,2,1]]

现在,“平均值”列排在最前面:

In [41]: df
Out[41]: 
   mean         4         3         2         1
0     1  0.190717  0.712833  0.043387  0.915661
1     1  0.617472  0.771080  0.590779  0.424771
2     1  0.155563  0.829491  0.989798  0.085894
3     1  0.951802  0.616751  0.299708  0.104061
4     1  0.322311  0.105886  0.421360  0.528156
5     1  0.736652  0.195162  0.224656  0.082047
6     1  0.507564  0.586563  0.318016  0.558108
7     1  0.337060  0.921786  0.930248  0.375183
8     1  0.423398  0.110675  0.931756  0.182905
9     1  0.417808  0.304561  0.140873  0.310562

13
它会复制吗? - user3226167
47
如果你的数据框中有1000列,那么这并不是最好的答案。 - AGS
2
你最初声称似乎没有给 <df>.columns 分配值。 - 3pitt
18
这是针对少量列的最佳答案。 - RyanC
7
这只是@freddygv早期回答的复制。那个应该被接受为答案,而不是这个。 - James Hirschorn

366

82
这能否成为pandas未来的一个特性?比如像df.move(0, df.mean)这样的功能? - jason
10
美丽。而且它也发生在这个地方。 - cucu8
8
这是一种可扩展的解决方案,因为其他解决方案需要手动输入列名。 - CKM
16
这适用于原帖问题中创建新列的情况,但对于移动列则不适用;尝试移动会导致 *** ValueError: cannot insert mean, already exists - SpinUp __ A Davis
10
这是一个简洁的解决方案。现代API方法是:df.insert(0,'mean',df ['mean']) - Sumax
显示剩余6条评论

199

根据你的情况,

df = df.reindex(columns=['mean',0,1,2,3,4])

会完全按照您的要求执行。

在我的情况下(一般形式):

df = df.reindex(columns=sorted(df.columns))
df = df.reindex(columns=(['opened'] + list([a for a in df.columns if a != 'opened']) ))

2
我尝试设置 copy=False,但似乎 reindex_axis 仍然会创建一个副本。 - Konstantin
1
@Konstantin,你能否再提出一个关于这个问题的问题吗?这样会更好,可以获得更多的上下文信息。 - Alvaro Silvino
@Konstantin 只是好奇,您是否进行了调试以查看 copy=False 是否会创建一个副本?文档称,当 copy=True 时,reindex 会返回一个新对象,暗示它否则可能是同一个旧对象;如果是同一个对象,那么如何成为副本呢? - stucash

123
import numpy as np
import pandas as pd
df = pd.DataFrame()
column_names = ['x','y','z','mean']
for col in column_names: 
    df[col] = np.random.randint(0,100, size=10000)

您可以尝试以下解决方案:

解决方案 1:

df = df[ ['mean'] + [ col for col in df.columns if col != 'mean' ] ]

解决方案2:


df = df[['mean', 'x', 'y', 'z']]
解决方法 3:
col = df.pop("mean")
df = df.insert(0, col.name, col)

解决方案4:

df.set_index(df.columns[-1], inplace=True)
df.reset_index(inplace=True)

解决方案5:

cols = list(df)
cols = [cols[-1]] + cols[:-1]
df = df[cols]

解决方案6:

order = [1,2,3,0] # setting column's order
df = df[[df.columns[i] for i in order]]

时间比较:

解决方案1:

CPU时间:用户1.05毫秒,系统:35微秒,总共:1.08毫秒墙面时间:995微秒

解决方案2:

CPU时间:用户933微秒,系统:0纳秒,总共:933微秒 墙面时间:800微秒

解决方案3:

CPU时间:用户0纳秒,系统:1.35毫秒,总共:1.35毫秒 墙面时间:1.08毫秒

解决方案4:

CPU时间:用户1.23毫秒,系统:45微秒,总共:1.27毫秒 墙面时间:986微秒

解决方案5:

CPU时间:用户1.09毫秒,系统:19微秒,总共:1.11毫秒 墙面时间:949微秒

解决方案6:

CPU时间:用户955微秒,系统:34微秒,总共:989微秒 墙面时间:859微秒


2
解决方案1正是我所需要的,因为我有太多列(53列),谢谢。 - ratnesh
2
@Pygirl 哪个值显示真实消耗的时间?(用户,系统,总计还是墙上时间) - sergzemsk
2
这对我来说是这个问题的最佳答案。有很多解决方案(包括我需要的一个)和简单的方法。谢谢! - Gustavo Rottgering
2
解决方案6(无列表推导):df = df.iloc[:, [1, 2, 3, 0]] - Dmitriy Work
2
@sergzemsk: 我通过墙上时间进行比较。 - Pygirl
2
方案3是列出的方案中唯一好的方法,因为它是唯一一个原地操作且不会干扰索引的方法。那些不是原地操作的方法是不可扩展的。 - Asclepius

83

您需要按照所需的顺序创建一个新的列列表,然后使用 df = df[cols] 来按照这个新的顺序重新排列列。

cols = ['mean']  + [col for col in df if col != 'mean']
df = df[cols]

你也可以采用更一般的方法。在本例中,最后一列(由-1表示)被插入为第一列。

cols = [df.columns[-1]] + [col for col in df if col != df.columns[-1]]
df = df[cols]

如果数据框中存在需要排序的列,您也可以使用这种方法对列进行重新排序,使它们按照所需的顺序排列。

inserted_cols = ['a', 'b', 'c']
cols = ([col for col in inserted_cols if col in df] 
        + [col for col in df if col not in inserted_cols])
df = df[cols]

73
假设您有一个名为df的数据框,其中包含ABC列。

最简单的方法是:

df = df.reindex(['B','C','A'], axis=1)

这个选项的一个很棒的特点是你可以在pandas管道操作中使用它! - cheevahagadog
2
请注意,这只会返回重新索引的数据框 - 不会更改正在使用的“df”实例。如果您想使用重新索引的df,请使用返回的值:df2 = df.reindex(['B', 'C', 'A'], axis=1)。感谢您提供这个答案! - Andreas Forslöw
@cheevahagadog 很好的观点! - liangli
@AndreasForslöw 感谢您的关注。 - liangli

67

这个问题之前已经有了回答,但是现在reindex_axis已经被弃用了,所以我建议使用:

df = df.reindex(sorted(df.columns), axis=1)

对于那些想要指定顺序而不仅仅是排序的人,这里是详细的解决方案:

df = df.reindex(['the','order','you','want'], axis=1)

现在,你想如何对列名列表进行排序,这实际上不是一个 pandas 的问题,而是一个 Python 列表操作的问题。有很多方法可以做到这一点,我认为这个答案提供了一种非常简洁的方法。


23
不,那是不同的情况。那里用户想按名称对所有列进行排序。这里,他们想将一列移到第一列,同时保持其他列的顺序不变。 - smci
2
如果您不想对它们进行排序怎么办? - Chankey Pathak
答案与问题中的问题无关。 - mins
1
@mins,我希望上面的编辑已经足够清晰了。 :) - dmvianna
您的编辑现在展示了一个解决问题的可行方案。谢谢。 - mins
显示剩余2条评论

66

如果您的列名太长而无法手动输入,则可以通过一个整数列表指定新顺序,其中包含位置:

数据:

          0         1         2         3         4      mean
0  0.397312  0.361846  0.719802  0.575223  0.449205  0.500678
1  0.287256  0.522337  0.992154  0.584221  0.042739  0.485741
2  0.884812  0.464172  0.149296  0.167698  0.793634  0.491923
3  0.656891  0.500179  0.046006  0.862769  0.651065  0.543382
4  0.673702  0.223489  0.438760  0.468954  0.308509  0.422683
5  0.764020  0.093050  0.100932  0.572475  0.416471  0.389390
6  0.259181  0.248186  0.626101  0.556980  0.559413  0.449972
7  0.400591  0.075461  0.096072  0.308755  0.157078  0.207592
8  0.639745  0.368987  0.340573  0.997547  0.011892  0.471749
9  0.050582  0.714160  0.168839  0.899230  0.359690  0.438500

通用示例:

new_order = [3,2,1,4,5,0]
print(df[df.columns[new_order]])  

          3         2         1         4      mean         0
0  0.575223  0.719802  0.361846  0.449205  0.500678  0.397312
1  0.584221  0.992154  0.522337  0.042739  0.485741  0.287256
2  0.167698  0.149296  0.464172  0.793634  0.491923  0.884812
3  0.862769  0.046006  0.500179  0.651065  0.543382  0.656891
4  0.468954  0.438760  0.223489  0.308509  0.422683  0.673702
5  0.572475  0.100932  0.093050  0.416471  0.389390  0.764020
6  0.556980  0.626101  0.248186  0.559413  0.449972  0.259181
7  0.308755  0.096072  0.075461  0.157078  0.207592  0.400591
8  0.997547  0.340573  0.368987  0.011892  0.471749  0.639745
9  0.899230  0.168839  0.714160  0.359690  0.438500  0.050582

尽管看起来我只是在以不同的顺序显式地输入列名,但是存在一个名为“mean”的列应该表明new_order与实际位置而非列名有关。

对于OP问题的特定情况:

new_order = [-1,0,1,2,3,4]
df = df[df.columns[new_order]]
print(df)

       mean         0         1         2         3         4
0  0.500678  0.397312  0.361846  0.719802  0.575223  0.449205
1  0.485741  0.287256  0.522337  0.992154  0.584221  0.042739
2  0.491923  0.884812  0.464172  0.149296  0.167698  0.793634
3  0.543382  0.656891  0.500179  0.046006  0.862769  0.651065
4  0.422683  0.673702  0.223489  0.438760  0.468954  0.308509
5  0.389390  0.764020  0.093050  0.100932  0.572475  0.416471
6  0.449972  0.259181  0.248186  0.626101  0.556980  0.559413
7  0.207592  0.400591  0.075461  0.096072  0.308755  0.157078
8  0.471749  0.639745  0.368987  0.340573  0.997547  0.011892
9  0.438500  0.050582  0.714160  0.168839  0.899230  0.359690

这种方法的主要问题在于,多次调用相同的代码会产生不同的结果,因此需要小心 :)


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