Przenieś kolumnę według nazwy na początek tabeli w pandach

103

Oto mój 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

Jak mogę przenieść kolumnę według nazwy ( "Mid") na początek tabeli, indeks 0. Tak powinien wyglądać wynik:

                             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

Mój obecny kod przenosi kolumnę według indeksu przy użyciu, df.columns.tolist()ale chciałbym przesunąć ją według nazwy.

Boosted_d16
źródło

Odpowiedzi:

121

Możemy użyć ixdo zmiany kolejności, przekazując 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.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

Inną metodą jest wzięcie odniesienia do kolumny i ponowne włożenie go z przodu:

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

Możesz również użyć, locaby osiągnąć ten sam wynik, ixktóry zostanie wycofany w przyszłej wersji pand 0.20.0:

df = df.loc[:, cols]
EdChum
źródło
Informacje na temat .locpowinny znaleźć się na górze, zamiast.ix
Gonçalo Peres 龚燿禄
57

Może czegoś mi brakuje, ale wiele z tych odpowiedzi wydaje się zbyt skomplikowanych. Powinieneś móc po prostu ustawić kolumny na jednej liście:

Kolumna do przodu:

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

Lub jeśli zamiast tego chcesz przenieść go do tyłu:

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

Lub jeśli chcesz przenieść więcej niż jedną kolumnę:

cols_to_move = ['Mid', 'Zsore']
df           = df[ cols_to_move + [ col for col in df.columns if col not in cols_to_move ] ]
elPastor
źródło
Dla kogokolwiek innego upewnij się, że dla wielu kolumn używasz opcji 3. Opcja 1 z wieloma kolumnami nie usunie Mid& Zscorez kolumny z pierwotnej pozycji. Znalazłem to z Grouperbłędem podczas próby grupowania, gdy ta sama kolumna była tam dwa razy.
775
46

Możesz użyć funkcji df.reindex () w pandach. df jest

                      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

zdefiniuj listę nazw kolumn

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

przenieś nazwę kolumny w dowolne miejsce

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

następnie użyj df.reindex()funkcji, aby zmienić kolejność

df = df.reindex(columns= cols)

wyjście to: 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
Sachinmm
źródło
37

Wolę takie rozwiązanie:

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

Czytanie jest prostsze i szybsze niż inne sugerowane odpowiedzi.

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

Ocena wydajności:

W tym teście w każdym powtórzeniu ostatnia kolumna jest przesuwana do przodu. Metody lokalne na ogół działają lepiej. Chociaż rozwiązanie firmy citynorman można stworzyć na miejscu, metoda Eda .locChuma oparta na metodzie Sachinnma reindexnie może.

Podczas gdy inne metody są ogólne, rozwiązanie Citynorman ogranicza się do pos=0. Nie zauważyłem żadnej różnicy w wydajności między df.loc[cols]i df[cols], dlatego nie uwzględniłem innych sugestii.

Testowałem z Pythonem 3.6.8 i pandami 0.24.2 na MacBooku Pro (połowa 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))

Wyniki :

# 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)
normanius
źródło
2
Świetne rozwiązanie. Nie powinniśmy jednak jawnie przypisywać zmodyfikowanego pliku df z wstawioną kolumną do oryginalnego pliku df. Więc zamiast tego df = df.insert(0, col.name, col)musimy zrobić df.insert(0, col.name, col). Masz go jednak poprawnie w funkcji move_column_inplace().
melihozbek
1
Dzięki @normanius. Widzę, że ciężko pracowałem w Laboratorium Dextera. :-) Świetne rozwiązanie. Brzytwa Ockhama. Prosty i elegancki.
brohjoe,
Ja też wolę to rozwiązanie :)
user88484
19

Nie podobało mi się, jak musiałem wyraźnie określić wszystkie inne kolumny w innych rozwiązaniach, więc to działało najlepiej dla mnie. Chociaż może to być powolne w przypadku dużych ramek danych ...?

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

citynorman
źródło
Wykorzystuje to, że obecne wersje reset_index()wstawiają porzucony indeks na pierwszej pozycji. Należy jednak pamiętać, że to zachowanie nie jest określone w dokumentacji .
normanius
1
Jeśli chodzi o wydajność, zobacz moją odpowiedź. Korzystne jest używanie inplace=Truezarówno do, jak set_index()i reset_index().
normanius
9

Oto ogólny zestaw kodu, którego często używam do zmiany położenia kolumn. Może ci się to przydać.

cols = df.columns.tolist()
n = int(cols.index('Mid'))
cols = [cols[n]] + cols[:n] + cols[n+1:]
df = df[cols]
Bhagabat Behera
źródło
3
najlepiej wyjaśnij swoją odpowiedź i wyjaśnij, co sprawia, że ​​jest to dobre rozwiązanie, a nie tylko publikuj fragment kodu. Ryzykujesz przegłosowanie
tjebo
5

Aby zmienić kolejność wierszy DataFrame, użyj listy w następujący sposób.

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

To sprawia, że ​​jest oczywiste, co zostało zrobione podczas późniejszego czytania kodu. Użyj również:

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

Następnie wytnij i wklej, aby zmienić kolejność.


W przypadku ramki DataFrame z wieloma kolumnami przechowuj listę kolumn w zmiennej i umieść żądaną kolumnę na początku listy. Oto przykład:

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]

Teraz df.columnsma.

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)
Dustin Helliwell
źródło
A co, jeśli pracujesz z DataFrame składającą się z 1001 kolumn?
normanius
Koncepcja jest taka sama, jednak przy wielu kolumnach kolumny powinny być przechowywane na liście i należy nią manipulować. Zobacz na przykład moje zmiany powyżej. Mój przykład jest w rzeczywistości taki sam jak stackoverflow.com/a/51009742/5827921 .
Dustin Helliwell
1

Oto bardzo prosta odpowiedź.

Nie zapomnij o dwóch (()) nawiasach kwadratowych wokół nazw kolumn, w przeciwnym razie spowoduje to błąd.


# 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
rra
źródło
najwyraźniej OP nie chce jawnie przeliterować nazw kolumn. W niektórych przypadkach przy bardzo szerokich ramkach danych może to być nawet niemożliwe.
Ledger Yu
0

Najprostszą rzeczą, jaką możesz wypróbować, jest:

df=df[[ 'Mid',   'Upper',   'Lower', 'Net'  , 'Zsore']]
NeelMani Shrivastava
źródło