Move column by name to front of table in pandas
Asked Answered
H

13

183

Here is my df:

                             Net   Upper   Lower  Mid  Zsore
Answer option                                                
More than once a day          0%   0.22%  -0.12%   2    65 
Once a day                    0%   0.32%  -0.19%   3    45
Several times a week          2%   2.45%   1.10%   4    78
Once a week                   1%   1.63%  -0.40%   6    65

How can I move a column by name ("Mid") to the front of the table, index 0. This is what the result should look like:

                             Mid   Upper   Lower  Net  Zsore
Answer option                                                
More than once a day          2   0.22%  -0.12%   0%    65 
Once a day                    3   0.32%  -0.19%   0%    45
Several times a week          4   2.45%   1.10%   2%    78
Once a week                   6   1.63%  -0.40%   1%    65

My current code moves the column by index using df.columns.tolist() but I'd like to shift it by name.

Hourigan answered 4/8, 2014 at 15:21 Comment(0)
L
160

We can use loc to reorder by passing a list:

In [27]:
# get a list of columns
cols = list(df)
# move the column to head of list using index, pop and insert
cols.insert(0, cols.pop(cols.index('Mid')))
cols
Out[27]:
['Mid', 'Net', 'Upper', 'Lower', 'Zsore']
In [28]:
# use ix to reorder
df = df.loc[:, cols]
df
Out[28]:
                      Mid Net  Upper   Lower  Zsore
Answer_option                                      
More_than_once_a_day    2  0%  0.22%  -0.12%     65
Once_a_day              3  0%  0.32%  -0.19%     45
Several_times_a_week    4  2%  2.45%   1.10%     78
Once_a_week             6  1%  1.63%  -0.40%     65

Another method is to take a reference to the column and reinsert it at the front:

In [39]:
mid = df['Mid']
df.drop(labels=['Mid'], axis=1,inplace = True)
df.insert(0, 'Mid', mid)
df
Out[39]:
                      Mid Net  Upper   Lower  Zsore
Answer_option                                      
More_than_once_a_day    2  0%  0.22%  -0.12%     65
Once_a_day              3  0%  0.32%  -0.19%     45
Several_times_a_week    4  2%  2.45%   1.10%     78
Once_a_week             6  1%  1.63%  -0.40%     65

You can, with very early versions of Pandas, also use ix to achieve the same results:

df = df.ix[:, cols]

But ix was deprecated from pandas 0.20.0 onwards and was discontinued as of Pandas 1.0.

Latoshalatouche answered 4/8, 2014 at 15:30 Comment(1)
I also use .loc with a list to re-order columns. I frequently want to move a newly-created column (at the far right) to the front, (i.e. left), for which I use df.loc[:, np.roll(df.columns, 1)]. Not sure whether that's easier to read than the list comprehensions others have noted elsewhere on this page, but I use numpy a lot so I find it easy. Cheers!Rawhide
J
142

Maybe I'm missing something, but a lot of these answers seem overly complicated. You should be able to just set the columns within a single list:

Column to the front:

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

Or if instead, you want to move it to the back:

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

Or if you wanted to move more than one column:

cols_to_move = ['Mid', 'Zsore']
df           = df[ cols_to_move + [ col for col in df.columns if col not in cols_to_move ] ]
Johannesburg answered 6/6, 2019 at 14:27 Comment(3)
For anyone else, make sure for multiple columns you use option 3. Option 1 with multiple columns won't delete Mid & Zscore from column from the original position. I found this out with a Grouper error trying to groupby when the same column was there twice.Yetac
@Yetac I think that only would have happened if you did if col != 'Mid' or col != 'Zscore' -- with if col != 'Mid' and col != 'Zscore' it will not duplicate the columns. Or even better: if col not in ('Mid', 'Zscore').Hornbook
Yes the 3rd piece you offered is the 3rd option I referenced. It is the cleanest way to go about multiple columns.Yetac
O
126

I prefer this solution:

col = df.pop("Mid")
df.insert(0, col.name, col)

It's simpler to read and faster than other suggested answers.

def move_column_inplace(df, col, pos):
    col = df.pop(col)
    df.insert(pos, col.name, col)

Performance assessment:

For this test, the currently last column is moved to the front in each repetition. In-place methods generally perform better. While citynorman's solution can be made in-place, Ed Chum's method based on .loc and sachinnm's method based on reindex cannot.

While other methods are generic, citynorman's solution is limited to pos=0. I didn't observe any performance difference between df.loc[cols] and df[cols], which is why I didn't include some other suggestions.

Original system (2019): Python 3.6.8 and pandas 0.24.2 on a MacBook Pro (Mid 2015).
Current system (2022): Python 3.10.5 and pandas 1.4.3 on a MacBook Pro (2021, Apple M1).

import numpy as np
import pandas as pd

n_cols = 11
df = pd.DataFrame(np.random.randn(200000, n_cols),
                  columns=range(n_cols))

def move_column_inplace(df, col, pos):
    col = df.pop(col)
    df.insert(pos, col.name, col)

def move_to_front_normanius_inplace(df, col):
    move_column_inplace(df, col, 0)
    return df

def move_to_front_chum(df, col):
    cols = list(df)
    cols.insert(0, cols.pop(cols.index(col)))
    return df.loc[:, cols]

def move_to_front_chum_inplace(df, col):
    col = df[col]
    df.drop(col.name, axis=1, inplace=True)
    df.insert(0, col.name, col)
    return df

def move_to_front_elpastor(df, col):
    cols = [col] + [ c for c in df.columns if c!=col ]
    return df[cols] # or df.loc[cols]

def move_to_front_sachinmm(df, col):
    cols = df.columns.tolist()
    cols.insert(0, cols.pop(cols.index(col)))
    df = df.reindex(columns=cols, copy=False)
    return df

def move_to_front_citynorman_inplace(df, col):
    # This approach exploits that reset_index() moves the index
    # at the first position of the data frame.
    df.set_index(col, inplace=True)
    df.reset_index(inplace=True)
    return df

def test(method, df):
    col = np.random.randint(0, n_cols)
    method(df, col)

col = np.random.randint(0, n_cols)
ret_mine = move_to_front_normanius_inplace(df.copy(), col)
ret_chum1 = move_to_front_chum(df.copy(), col)
ret_chum2 = move_to_front_chum_inplace(df.copy(), col)
ret_elpas = move_to_front_elpastor(df.copy(), col)
ret_sach = move_to_front_sachinmm(df.copy(), col)
ret_city = move_to_front_citynorman_inplace(df.copy(), col)

# Assert equivalence of solutions.
assert(ret_mine.equals(ret_chum1))
assert(ret_mine.equals(ret_chum2))
assert(ret_mine.equals(ret_elpas))
assert(ret_mine.equals(ret_sach))
assert(ret_mine.equals(ret_city))

Results:

# For n_cols = 11:
%timeit test(move_to_front_normanius_inplace, df)
# 137 µs ± 692 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 177 µs ± 10.7 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit test(move_to_front_sachinmm, df)
# 821 µs ± 11.8 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%timeit test(move_to_front_chum, df)
# 926 µs ± 10.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%timeit test(move_to_front_elpastor, df)
# 901 µs ± 6.44 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 3.25 ms ± 32.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


# For n_cols = 31:
%timeit test(move_to_front_normanius_inplace, df)
# 188 µs ± 3.46 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 214 µs ± 649 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
%timeit test(move_to_front_sachinmm, df)
# 5.17 ms ± 68.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum, df)
# 5.52 ms ± 82.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_elpastor, df)
# 5.48 ms ± 198 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 14.7 ms ± 317 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Above are the updated values for a rerun in 2022. The rankings have remained stable over the past years for different systems, although the absolute numbers have decreased by factors between 2 and 10, from which citynorman's solution and my solution (normanius) have benefited the most.

Ophelia answered 4/11, 2019 at 2:59 Comment(4)
Great solution. However, we should not assign the modified df with the inserted column to the original df explicitly. So instead of df = df.insert(0, col.name, col), we need to do df.insert(0, col.name, col). You have it correctly in the function move_column_inplace() though.Eligibility
Thanks @normanius. Been working hard in Dexter's Laboratory I see. :-) Great solution. Occam's Razor. Simple and elegant.Pact
I also prefer this solution :)Daglock
What about test with multiple columns move? :)Donee
Z
53

You can use the df.reindex() function in pandas. df is

                      Net  Upper   Lower  Mid  Zsore
Answer option                                      
More than once a day  0%  0.22%  -0.12%    2     65
Once a day            0%  0.32%  -0.19%    3     45
Several times a week  2%  2.45%   1.10%    4     78
Once a week           1%  1.63%  -0.40%    6     65

define an list of column names

cols = df.columns.tolist()
cols
Out[13]: ['Net', 'Upper', 'Lower', 'Mid', 'Zsore']

move the column name to wherever you want

cols.insert(0, cols.pop(cols.index('Mid')))
cols
Out[16]: ['Mid', 'Net', 'Upper', 'Lower', 'Zsore']

then use df.reindex() function to reorder

df = df.reindex(columns= cols)

out put is: df

                      Mid  Upper   Lower Net  Zsore
Answer option                                      
More than once a day    2  0.22%  -0.12%  0%     65
Once a day              3  0.32%  -0.19%  0%     45
Several times a week    4  2.45%   1.10%  2%     78
Once a week             6  1.63%  -0.40%  1%     65
Zinciferous answered 14/7, 2015 at 1:11 Comment(0)
J
25

I didn't like how I had to explicitly specify all the other column in the other solutions.

cfg_col_sel = ['Mid', 'Zscore']
cfg_col_sel = cfg_col_sel+[s for s in df.columns if not s in cfg_col_sel]
df = df[cfg_col_sel]

This is another way of doing it but less flexible

df = df.set_index('Mid').reset_index()

Johnsiejohnson answered 1/12, 2017 at 17:14 Comment(2)
This exploits that current versions of reset_index() insert the dropped index at the first position. Note, however, that this behavior is not specified in the docs.Ophelia
As for the performance, see my answer. It's advantageous to use inplace=True for both set_index() and reset_index().Ophelia
W
11

Here is a generic set of code that I frequently use to rearrange the position of columns. You may find it useful.

cols = df.columns.tolist()
n = int(cols.index('Mid'))
cols = [cols[n]] + cols[:n] + cols[n+1:]
df = df[cols]
Wrongdoer answered 24/6, 2018 at 12:0 Comment(1)
ideally, explain your answer and what makes it a good solution, and not only post a piece of code. You are risking downvotingKevyn
F
5

To reorder the rows of a DataFrame just use a list as follows.

df = df[['Mid', 'Net', 'Upper', 'Lower', 'Zsore']]

This makes it very obvious what was done when reading the code later. Also use:

df.columns
Out[1]: Index(['Net', 'Upper', 'Lower', 'Mid', 'Zsore'], dtype='object')

Then cut and paste to reorder.


For a DataFrame with many columns, store the list of columns in a variable and pop the desired column to the front of the list. Here is an example:

cols = [str(col_name) for col_name in range(1001)]
data = np.random.rand(10,1001)
df = pd.DataFrame(data=data, columns=cols)

mv_col = cols.pop(cols.index('77'))
df = df[[mv_col] + cols]

Now df.columns has.

Index(['77', '0', '1', '2', '3', '4', '5', '6', '7', '8',
       ...
       '991', '992', '993', '994', '995', '996', '997', '998', '999', '1000'],
      dtype='object', length=1001)
Fretful answered 26/6, 2019 at 23:50 Comment(2)
What if you work with a DataFrame consisting of 1001 columns?Ophelia
The concept is the same, however with many columns the columns should be stored in a list and the list should be manipulated. See my edits above for an example. My example is effectively the same as https://mcmap.net/q/135780/-move-column-by-name-to-front-of-table-in-pandas.Fretful
E
3
df.set_index('Mid').reset_index()

seems to be a pretty easy way about this.

Eparch answered 17/2, 2021 at 17:24 Comment(0)
A
3

If you want to move a column to the front of the dataframe, you can use use set_index().

df.set_index(df.pop('column_name'), inplace=True)
df.reset_index(inplace=True)

You first need to set the column you want to bring to the front as the index of the dataframe (and we do a pop in order to drop the column from the original dataframe before setting it as the index in order to avoid name collision in the next action) and finally call reset_index() to make the old index the first column of the dataframe.


For more details see How to change the order of dataframe columns in pandas.

Apelles answered 15/8, 2021 at 22:0 Comment(1)
This one resets your index, which may cause problems elsewhere.Wrangle
P
2

Here is a very simple answer to this.

Don't forget the two (()) 'brackets' around columns names.Otherwise, it'll give you an error.


# here you can add below line and it should work 
df = df[list(('Mid','Upper', 'Lower', 'Net','Zsore'))]
df

                             Mid   Upper   Lower  Net  Zsore
Answer option                                                
More than once a day          2   0.22%  -0.12%   0%    65 
Once a day                    3   0.32%  -0.19%   0%    45
Several times a week          4   2.45%   1.10%   2%    78
Once a week                   6   1.63%  -0.40%   1%    65
Photomap answered 18/6, 2020 at 19:11 Comment(1)
clearly OP doesn't want to explicitly spell out the column names. In some cases with very wide dataframes it might not even be possible.Tuque
P
1

You can use movecolumn package in Python to move columns:

pip install movecolumn

Then you can write your code as:

import movecolumn as mc
mc.MoveTo1(df,'mid')

Hope that helps.

P.S : The package can be found here. https://pypi.org/project/movecolumn/

Pentothal answered 9/8, 2022 at 20:31 Comment(0)
K
1

Easy and quick solution::

For pandas >= 1.3 (Edited in 2022):

df.insert(0, 'mean', df.pop('mean'))

How about (for Pandas < 1.3, the original answer)

df.insert(0, 'mean', df['mean'])
Karakalpak answered 12/10, 2022 at 20:56 Comment(0)
P
0

The most simplist thing you can try is:

df=df[[ 'Mid',   'Upper',   'Lower', 'Net'  , 'Zsore']]
Porche answered 8/7, 2020 at 20:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.