Mover la columna por nombre al frente de la tabla en pandas


97

Aquí está mi 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

¿Cómo puedo mover una columna por nombre ( "Mid") al frente de la tabla, índice 0? Así es como debería verse el resultado:

                             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

Mi código actual mueve la columna por índice usando df.columns.tolist()pero me gustaría cambiarlo por nombre.

Respuestas:


114

Podemos usar ixpara reordenar pasando una lista:

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.ix[:, 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

Otro método es tomar una referencia a la columna y reinsertarla en el frente:

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

También puede usar locpara lograr el mismo resultado que ixquedará obsoleto en una versión futura de pandas a 0.20.0partir de ahora:

df = df.loc[:, cols]

54

Quizás me esté perdiendo algo, pero muchas de estas respuestas parecen demasiado complicadas. Debería poder establecer las columnas dentro de una sola lista:

Columna al frente:

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

O si, en cambio, quieres moverlo hacia atrás:

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

O si desea mover más de una columna:

cols_to_move = ['Mid', 'Zsore']
df           = df[ cols_to_move + [ col for col in df.columns if col not in cols_to_move ] ]

Para cualquier otra persona, asegúrese de utilizar la opción 3 para varias columnas. La opción 1 con varias columnas no eliminará Mid& Zscorede la columna de la posición original. Descubrí esto con un Groupererror al intentar agrupar por cuando la misma columna estaba allí dos veces.
the775

46

Puede utilizar la función df.reindex () en pandas. df es

                      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

definir una lista de nombres de columnas

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

mueve el nombre de la columna a donde quieras

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

luego usa la df.reindex()función para reordenar

df = df.reindex(columns= cols)

fuera puesto es: 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

31

Prefiero esta solución:

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

Es más sencillo de leer y más rápido que otras respuestas sugeridas.

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

Evaluación del desempeño:

Para esta prueba, la última columna actual se mueve al frente en cada repetición. Los métodos in situ generalmente funcionan mejor. Si bien la solución de citynorman se puede realizar en el lugar, el método de Ed Chum basado en .locy el método de sachinnm basado en reindexno puede.

Mientras que otros métodos son genéricos, la solución de citynorman se limita a pos=0. No observé ninguna diferencia de rendimiento entre df.loc[cols]y df[cols], razón por la cual no incluí otras sugerencias.

Probé con python 3.6.8 y pandas 0.24.2 en una MacBook Pro (mediados de 2015).

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))

Resultados :

# For n_cols = 11:
%timeit test(move_to_front_normanius_inplace, df)
# 1.05 ms ± 42.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 1.68 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit test(move_to_front_sachinmm, df)
# 3.24 ms ± 96.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum, df)
# 3.84 ms ± 114 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_elpastor, df)
# 3.85 ms ± 58.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 9.67 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


# For n_cols = 31:
%timeit test(move_to_front_normanius_inplace, df)
# 1.26 ms ± 31.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_citynorman_inplace, df)
# 1.95 ms ± 260 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_sachinmm, df)
# 10.7 ms ± 348 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum, df)
# 11.5 ms ± 869 µs per loop (mean ± std. dev. of 7 runs, 100 loops each
%timeit test(move_to_front_elpastor, df)
# 11.4 ms ± 598 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(move_to_front_chum_inplace, df)
# 31.4 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

2
Gran solucion Sin embargo, no debemos asignar el df modificado con la columna insertada al df original explícitamente. Entonces, en lugar de df = df.insert(0, col.name, col), tenemos que hacerlo df.insert(0, col.name, col). Sin embargo, lo tienes correctamente en la función move_column_inplace().
melihozbek

1
Gracias @normanius. He estado trabajando duro en el laboratorio de Dexter, veo. :-) Gran solución. La navaja de Occam. Simple y elegante.
brohjoe

También prefiero esta solución :)
user88484

19

No me gustó cómo tuve que especificar explícitamente todas las demás columnas en las otras soluciones, por lo que esto funcionó mejor para mí. ¿Aunque podría ser lento para grandes marcos de datos ...?

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


Esto aprovecha que las versiones actuales de reset_index()insertan el índice eliminado en la primera posición. Sin embargo, tenga en cuenta que este comportamiento no se especifica en los documentos .
normanius

1
En cuanto a la actuación, mira mi respuesta. Es ventajoso usarlo inplace=Truepara ambos set_index()y reset_index().
normanius

9

Aquí hay un conjunto genérico de código que utilizo con frecuencia para reorganizar la posición de las columnas. Lo podrías encontrar útil.

cols = df.columns.tolist()
n = int(cols.index('Mid'))
cols = [cols[n]] + cols[:n] + cols[n+1:]
df = df[cols]

3
idealmente, explique su respuesta y qué la convierte en una buena solución, y no solo publique un fragmento de código. Se arriesga a votar negativamente
Tjebo

5

Para reordenar las filas de un DataFrame, simplemente use una lista de la siguiente manera.

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

Esto hace que sea muy obvio lo que se hizo al leer el código más tarde. También use:

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

Luego corte y pegue para reordenar.


Para un DataFrame con muchas columnas, almacene la lista de columnas en una variable y coloque la columna deseada al principio de la lista. Aquí hay un ejemplo:

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]

Ahora df.columnstiene.

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)

¿Qué pasa si trabaja con un DataFrame que consta de 1001 columnas?
Normanius

El concepto es el mismo, sin embargo, con muchas columnas, las columnas deben almacenarse en una lista y la lista debe manipularse. Consulte mis ediciones anteriores para ver un ejemplo. Mi ejemplo es efectivamente el mismo que stackoverflow.com/a/51009742/5827921 .
Dustin Helliwell

1

Aquí hay una respuesta muy simple a esto.

No olvide los dos (()) 'corchetes' alrededor de los nombres de las columnas, de lo contrario, le dará un 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

claramente, OP no quiere deletrear explícitamente los nombres de las columnas. En algunos casos con marcos de datos muy amplios, es posible que ni siquiera sea posible.
Ledger Yu

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.