Mova a coluna pelo nome para a frente da mesa nos pandas


100

Aqui está meu 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

Como posso mover uma coluna por nome ( "Mid") para a frente da tabela, índice 0. Esta é a aparência do 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

Meu código atual move a coluna por índice usando, df.columns.tolist()mas eu gostaria de mudá-lo por nome.

Respostas:


120

Podemos usar ixpara reordenar passando uma 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

Outro método é pegar uma referência para a coluna e reinseri-la na 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

Você também pode usar locpara obter o mesmo resultado, pois ixterá seu uso suspenso em uma versão futura do pandas 0.20.0:

df = df.loc[:, cols]

56

Talvez eu esteja faltando alguma coisa, mas muitas dessas respostas parecem excessivamente complicadas. Você deve ser capaz de definir apenas as colunas em uma única lista:

Coluna à frente:

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

Ou se, em vez disso, você quiser movê-lo para trás:

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

Ou se você quiser mover mais de uma coluna:

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

Para qualquer outra pessoa, certifique-se de usar a opção 3 para várias colunas. A opção 1 com várias colunas não excluirá Mide Zscoreda coluna da posição original. Descobri isso com um Groupererro ao tentar agrupar quando a mesma coluna estava lá duas vezes.
the775

46

Você pode usar a função df.reindex () nos pandas. 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

definir uma lista de nomes de coluna

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

mova o nome da coluna para onde quiser

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

então use a df.reindex()função para reordenar

df = df.reindex(columns= cols)

a saída é: 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

37

Eu prefiro esta solução:

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

É mais simples de ler e mais rápido do que outras respostas sugeridas.

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

Avaliação de desempenho:

Para este teste, a última coluna atual é movida para a frente em cada repetição. Os métodos no local geralmente funcionam melhor. Embora a solução de citynorman possa ser feita no local, o método de Ed Chum baseado em .loce o método de sachinnm baseado em reindexnão podem.

Embora outros métodos sejam genéricos, a solução de citynorman é limitada a pos=0. Não observei nenhuma diferença de desempenho entre df.loc[cols]e df[cols], por isso não incluí algumas outras sugestões.

Testei com python 3.6.8 e pandas 0.24.2 em um MacBook Pro (meados 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
Ótima solução. No entanto, não devemos atribuir o df modificado com a coluna inserida ao df original explicitamente. Então, em vez de df = df.insert(0, col.name, col), precisamos fazer df.insert(0, col.name, col). Você o tem corretamente na função move_column_inplace().
melihozbek

1
Obrigado @normanius. Tenho trabalhado muito no Laboratório de Dexter, pelo que vejo. :-) Ótima solução. Navalha de Occam. Simples e elegante.
brohjoe

Eu também prefiro esta solução :)
user88484

19

Não gostei de como tive que especificar explicitamente todas as outras colunas nas outras soluções, então isso funcionou melhor para mim. Embora possa ser lento para grandes dataframes ...?

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


Isso explora que as versões atuais do reset_index()inserem o índice eliminado na primeira posição. Observe, no entanto, que esse comportamento não é especificado nos documentos .
normanius

1
Quanto ao desempenho, veja minha resposta. É vantajoso usar inplace=Truepara ambos set_index()e reset_index().
normanius

9

Aqui está um conjunto genérico de código que uso com frequência para reorganizar a posição das colunas. Você pode achar útil.

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

3
de preferência, explique sua resposta e o que a torna uma boa solução, e não apenas poste um trecho de código. Você está se arriscando a votar negativamente
tjebo

5

Para reordenar as linhas de um DataFrame, basta usar a lista a seguir.

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

Isso torna muito óbvio o que foi feito ao ler o código posteriormente. Também use:

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

Em seguida, corte e cole para reorganizar.


Para um DataFrame com muitas colunas, armazene a lista de colunas em uma variável e coloque a coluna desejada no início da lista. Aqui está um exemplo:

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]

Agora df.columnssim.

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)

E se você trabalhar com um DataFrame que consiste em 1001 colunas?
normanius

O conceito é o mesmo, porém com muitas colunas as colunas devem ser armazenadas em uma lista e a lista deve ser manipulada. Veja minhas edições acima para um exemplo. Meu exemplo é efetivamente o mesmo que stackoverflow.com/a/51009742/5827921 .
Dustin Helliwell

1

Aqui está uma resposta muito simples para isso.

Não se esqueça dos dois (()) 'colchetes' em torno dos nomes das colunas. Caso contrário, ocorrerá um erro.


# 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 não deseja explicitar os nomes das colunas. Em alguns casos, com dataframes muito amplos, pode nem ser possível.
Ledger Yu

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.