Usuń kolumnę z pand DataFrame

1323

Podczas usuwania kolumny w ramce danych używam:

del df['column_name']

I to działa świetnie. Dlaczego nie mogę użyć poniższych?

del df.column_name

Ponieważ można uzyskać dostęp do kolumny / serii as df.column_name, spodziewałem się, że to zadziała.

Jan
źródło
2
Uwaga: to pytanie jest omawiane na Meta .
RM

Odpowiedzi:

855

Jak się domyślacie, właściwa składnia to

del df['column_name']

Trudno jest del df.column_namepracować po prostu ze względu na ograniczenia składniowe w Pythonie. del df[name]zostaje przetłumaczone df.__delitem__(name)na okładki przez Python.

Wes McKinney
źródło
25
Zdaję sobie sprawę, że jest to bardzo stara „odpowiedź”, ale moja ciekawość jest wzbudzona - dlaczego jest to syntaktyczne ograniczenie Pythona? class A(object): def __init__(self): self.var = 1tworzy klasę, a potem a = A(); del a.vardziała dobrze ...
dwanderson
13
@dwanderson różnica polega na tym, że gdy kolumna ma zostać usunięta, DataFrame musi mieć własną obsługę „jak to zrobić”. W przypadku del df[name]zostaje przetłumaczone na df.__delitem__(name)metodę, którą DataFrame może wdrożyć i zmodyfikować zgodnie ze swoimi potrzebami. W przypadku del df.namezmiennej członka jest usuwana bez szansy na uruchomienie dowolnego kodu niestandardowego. Zastanów się nad własnym przykładem - czy możesz uzyskać del a.varwydruk „usuwania zmiennej”? Jeśli możesz, powiedz mi jak. Nie mogę :)
Yonatan,
8
@Yonatan Możesz do tego użyć docs.python.org/3/reference/datamodel.html#object.__delattr__ lub deskryptorów: docs.python.org/3/howto/descriptor.html
Eugene Pakhomov
5
Komentarz Yonatana Eugene'a dotyczy również Pythona 2; deskryptory są w Pythonie 2 od wersji 2.2 i spełnienie wymagań jest banalne;)
CS
1
Ta odpowiedź nie jest naprawdę poprawna - pandastwórcy tego nie zrobili , ale to nie znaczy, że jest to trudne.
wizzwizz4
2182

Najlepszym sposobem na to w pandach jest użycie drop:

df = df.drop('column_name', 1)

gdzie 1jest numerem osi ( 0dla wierszy i 1kolumn).

Aby usunąć kolumnę bez konieczności ponownego przypisywania df, możesz:

df.drop('column_name', axis=1, inplace=True)

Na koniec, aby upuścić według numeru kolumny zamiast według etykiety kolumny , spróbuj to usunąć, np. 1., 2. i 4. kolumna:

df = df.drop(df.columns[[0, 1, 3]], axis=1)  # df.columns is zero-based pd.Index 

Pracuje również ze składnią „tekstową” dla kolumn:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)
LondonRob
źródło
79
Czy delz jakiegoś powodu jest to zalecane ?
beardc
20
Chociaż ta metoda usuwania ma swoje zalety, ta odpowiedź tak naprawdę nie odpowiada na zadawane pytanie.
Paul
109
Prawda @Paul, ale ze względu na tytuł pytania większość osób przybywających tutaj zrobi to, próbując dowiedzieć się, jak usunąć kolumnę.
LondonRob
24
@beardc inną zaletą dropprzez delto, że droppozwala usunąć kilka kolumn na raz, należy wykonać W miejscu pracy, czy nie, a także usuwanie zapisów wzdłuż każdej osi (szczególnie przydatny do matrycy 3-D lub Panel)
płyty grzejne
8
Kolejną zaletą dropna delto, że spadek jest częścią API pandy i zawiera dokumentację.
modulitos
240

Posługiwać się:

columns = ['Col1', 'Col2', ...]
df.drop(columns, inplace=True, axis=1)

Spowoduje to usunięcie jednej lub więcej kolumn w miejscu. Pamiętaj, że inplace=Truezostał dodany w pandach v0.13 i nie będzie działać na starszych wersjach. W takim przypadku musisz przypisać wynik z powrotem:

df = df.drop(columns, axis=1)
Krishna Sankar
źródło
3
Uwaga na temat tej odpowiedzi: jeśli używana jest „lista”, nawiasy kwadratowe powinny zostać usunięte:df.drop(list,inplace=True,axis=1)
edesz
1
to naprawdę powinna być zaakceptowana odpowiedź, ponieważ wyjaśnia ona wyższość tej metody nad del- może upuścić więcej niż jedną kolumnę na raz.
dbliss
111

Upuść według indeksu

Usuń pierwszą, drugą i czwartą kolumnę:

df.drop(df.columns[[0,1,3]], axis=1, inplace=True)

Usuń pierwszą kolumnę:

df.drop(df.columns[[0]], axis=1, inplace=True)

Istnieje opcjonalny parametr, inplacedzięki czemu oryginalne dane można modyfikować bez tworzenia kopii.

Wyskoczył

Wybór kolumny, dodawanie, usuwanie

Usuń kolumnę column-name:

df.pop('column-name')

Przykłady:

df = DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6]), ('C', [7,8, 9])], orient='index', columns=['one', 'two', 'three'])

print df:

   one  two  three
A    1    2      3
B    4    5      6
C    7    8      9

df.drop(df.columns[[0]], axis=1, inplace=True) print df:

   two  three
A    2      3
B    5      6
C    8      9

three = df.pop('three') print df:

   two
A    2
B    5
C    8
jezrael
źródło
1
Jak mogę rzucić wiersz w pandy?
Kennet Celeste
2
@Yugi Możesz do tego użyć transponowanej ramki danych. ex - df.T.pop('A')
Clock Slave,
@ClockSlave To nie modyfikuje oryginału df. Możesz to zrobić, df = df.T; df.pop(index); df = df.Tale wydaje się to przesadne.
cs95,
Zamiast tego df.drop(df.columns[[0]], axis=1, inplace=True)nie wystarczy użyć df.drop([0], axis=1)?
Anirban Mukherjee,
1
@Anirban Mukherjee To zależy. Jeśli chcesz usunąć nazwę kolumny 0, to df.drop(0, axis=1)działa dobrze. Ale jeśli nie znasz nazwy kolumny i potrzebujesz usunąć pierwszą kolumnę, to musisz df.drop(df.columns[[0]], axis=1, inplace=True), wybierz pierwszą kolumnę według pozycji i upuść ją.
jezrael
71

Rzeczywiste pytanie, na które nie ma większości odpowiedzi tutaj:

Dlaczego nie mogę użyć del df.column_name?

Najpierw musimy zrozumieć problem, który wymaga od nas zanurzenia się w magicznych metodach Pythona .

Jak Wes wskazuje w swojej odpowiedzi del df['column']mapuje na magiczną metodę pytona ,df.__delitem__('column') która jest implementowana w pandach w celu upuszczenia kolumny

Jednak, jak wskazano w powyższym linku na temat magicznych metod Pythona :

W rzeczywistości __del__prawie nigdy nie należy go używać z powodu niepewnych okoliczności, w jakich się go nazywa; używaj go ostrożnie!

Można argumentować, że del df['column_name']nie należy go wykorzystywać ani zachęcać, a tym samym del df.column_namenie należy go nawet brać pod uwagę.

Jednak teoretycznie del df.column_namemogłyby być implemeted do pracy w pand wykorzystujących ten sposób magiczne__delattr__ . Wprowadza to jednak pewne problemy, problemy, które del df['column_name']już ma wdrożenie, ale w mniejszym stopniu.

Przykład problemu

Co jeśli zdefiniuję kolumnę w ramce danych o nazwie „dtypy” lub „kolumny”.

Załóżmy, że chcę usunąć te kolumny.

del df.dtypesspowodowałoby, że __delattr__metoda byłaby mylona, ​​tak jakby powinna usunąć atrybut „dtypes” lub kolumnę „dtypes”.

Pytania architektoniczne stojące za tym problemem

  1. Czy ramka danych to zbiór kolumn ?
  2. Czy ramka danych to zbiór wierszy ?
  3. Czy kolumna jest atrybutem ramki danych?

Odpowiedzi Pandy:

  1. Tak, na wszystkie sposoby
  2. No, ale jeśli chcesz go mieć, można użyć .ix, .locani .ilocmetod.
  3. Może chcesz odczytać dane? Zatem tak , chyba że nazwa atrybutu jest już zajęta przez inny atrybut należący do ramki danych. Czy chcesz zmodyfikować dane? Wtedy nie .

TLDR;

Nie możesz tego zrobić, del df.column_nameponieważ pandy mają dość dziko rozwiniętą architekturę, którą należy ponownie rozważyć, aby tego rodzaju dysonans poznawczy nie pojawił się u jej użytkowników.

Protip:

Nie używaj df.column_name, może być ładny, ale powoduje dysonans poznawczy

Cytaty Zen z Python, które pasują tutaj:

Istnieje wiele sposobów usuwania kolumny.

Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.

Kolumny są czasem atrybutami, a czasem nie.

Przypadki specjalne nie są wystarczająco wyjątkowe, aby złamać zasady.

Czy del df.dtypesusuwa atrybut dtypes lub kolumnę dtypes?

W obliczu dwuznaczności odmów pokusy zgadywania.

firelynx
źródło
„W rzeczywistości __del__prawie nigdy nie należy go używać ze względu na niepewne okoliczności, w jakich się go nazywa; używaj go ostrożnie!” jest tutaj zupełnie nieistotne, ponieważ stosowana jest tutaj metoda __delattr__.
pppery
1
@ppperry, którego zacytowałeś. chodzi o delwbudowane, a nie o .__del__metodę instancji. delWbudowane jest do mapowania __delattr__i __delitem__która jest, co buduję mój argument na. Może więc chcesz ponownie przeczytać to, co napisałem.
firelynx
1
__... __zostaje zinterpretowany jako śmiały znacznik przez StackExchange
pppery
2
„Nie używaj df.column_name, może być ładny, ale powoduje dysonans poznawczy” Co to znaczy? Nie jestem psychologiem, więc muszę to sprawdzić, aby zrozumieć, co masz na myśli. Również cytowanie Zen jest bez znaczenia, ponieważ istnieją setki prawidłowych sposobów robienia tego samego w pandach.
cs95
58

Przyjemnym dodatkiem jest możliwość upuszczania kolumn tylko wtedy, gdy istnieją . W ten sposób możesz objąć więcej przypadków użycia i spowoduje to usunięcie tylko istniejących kolumn z przekazanych do niego etykiet:

Po prostu dodaj błędy = „ignoruj” , na przykład:

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • Jest to nowość od pand 0.16.1. Dokumentacja jest tutaj .
eiTan LaVi
źródło
41

od wersji 0.16.1 możesz to zrobić

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')
sushmit
źródło
3
A to obsługuje także usuwanie wielu kolumn, z których niektóre nie muszą istnieć (tj. Bez zgłaszania błędów errors= 'ignore') df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore'), jeśli taka aplikacja jest pożądana!
mion
31

Dobrą praktyką jest zawsze stosowanie []zapisu. Jednym z powodów jest to, że notacja atrybutu ( df.column_name) nie działa w przypadku indeksów numerowanych:

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])

In [2]: df[1]
Out[2]:
0    2
1    5
Name: 1

In [3]: df.1
  File "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax
Andy Hayden
źródło
26

Odpowiedź Pandy 0,21+

Panda w wersji 0.21 dropnieznacznie zmieniła metodę, aby uwzględnić zarówno parametry, jak indexi columnsparametry, aby pasowały do ​​podpisu metod renamei reindex.

df.drop(columns=['column_a', 'column_c'])

Osobiście wolę używać axisparametru do oznaczania kolumn lub indeksu, ponieważ jest to dominujący parametr słowa kluczowego używany w prawie wszystkich metodach pand. Ale teraz masz kilka dodatkowych opcji w wersji 0.21.

Ted Petrou
źródło
1
df.drop (['column_a', 'column_c'], oś = 1) | na razie działa dla mnie
YouAreAwesome
21

W pandach 0.16.1+ można upuścić kolumny tylko wtedy, gdy istnieją zgodnie z rozwiązaniem opublikowanym przez @eiTanLaVi. Przed tą wersją można osiągnąć ten sam wynik dzięki warunkowemu zrozumieniu listy:

df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df], 
        axis=1, inplace=True)
Alexander
źródło
14

TL; DR

Dużo wysiłku, aby znaleźć nieco bardziej wydajne rozwiązanie. Trudno uzasadnić dodatkową złożoność, poświęcając jednocześnie prostotędf.drop(dlst, 1, errors='ignore')

df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1)

Preambuła
Usuwanie kolumny jest semantycznie takie samo jak wybieranie innych kolumn. Pokażę kilka dodatkowych metod do rozważenia.

Skupię się również na ogólnym rozwiązaniu polegającym na usuwaniu wielu kolumn naraz i umożliwieniu próby usunięcia kolumn nieobecnych.

Korzystanie z tych rozwiązań jest ogólne i będzie działać również w prostym przypadku.


Konfiguracja
Rozważ pd.DataFrame dflistę i do usunięciadlst

df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3))
dlst = list('HIJKLM')

df

   A  B  C  D  E  F  G  H  I   J
0  1  2  3  4  5  6  7  8  9  10
1  1  2  3  4  5  6  7  8  9  10
2  1  2  3  4  5  6  7  8  9  10

dlst

['H', 'I', 'J', 'K', 'L', 'M']

Wynik powinien wyglądać następująco:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Ponieważ zrównuję usuwanie kolumny z wyborem innych kolumn, podzielę ją na dwa typy:

  1. Wybór etykiety
  2. Wybór boolowski

Wybór etykiety

Zaczynamy od wytworzenia listy / tablicy etykiet reprezentujących kolumny, które chcemy zachować, i bez kolumn, które chcemy usunąć.

  1. df.columns.difference(dlst)

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
  2. np.setdiff1d(df.columns.values, dlst)

    array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
  3. df.columns.drop(dlst, errors='ignore')

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
  4. list(set(df.columns.values.tolist()).difference(dlst))

    # does not preserve order
    ['E', 'D', 'B', 'F', 'G', 'A', 'C']
  5. [x for x in df.columns.values.tolist() if x not in dlst]

    ['A', 'B', 'C', 'D', 'E', 'F', 'G']

Kolumny z etykiet
Aby porównać proces selekcji, załóż:

 cols = [x for x in df.columns.values.tolist() if x not in dlst]

Następnie możemy ocenić

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

Które oceniają:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Kawałek boolowski

Możemy skonstruować tablicę / listę wartości logicznych do krojenia

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

Kolumny z Boolean
Dla porównania

bools = [x not in dlst for x in df.columns.values.tolist()]
  1. df.loc[: bools]

Które oceniają:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

Solidny czas

Funkcje

setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst)
difference = lambda df, dlst: df.columns.difference(dlst)
columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore')
setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst))
comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst]

loc = lambda df, cols: df.loc[:, cols]
slc = lambda df, cols: df[cols]
ridx = lambda df, cols: df.reindex(columns=cols)
ridxa = lambda df, cols: df.reindex_axis(cols, 1)

isin = lambda df, dlst: ~df.columns.isin(dlst)
in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst)
comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()]
brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1)

Testowanie

res1 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc slc ridx ridxa'.split(),
        'setdiff1d difference columndrop setdifflst comprehension'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res2 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc'.split(),
        'isin in1d comp brod'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res = res1.append(res2).sort_index()

dres = pd.Series(index=res.columns, name='drop')

for j in res.columns:
    dlst = list(range(j))
    cols = list(range(j // 2, j + j // 2))
    d = pd.DataFrame(1, range(10), cols)
    dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100)
    for s, l in res.index:
        stmt = '{}(d, {}(d, dlst))'.format(s, l)
        setp = 'from __main__ import d, dlst, {}, {}'.format(s, l)
        res.at[(s, l), j] = timeit(stmt, setp, number=100)

rs = res / dres

rs

                          10        30        100       300        1000
Select Label                                                           
loc    brod           0.747373  0.861979  0.891144  1.284235   3.872157
       columndrop     1.193983  1.292843  1.396841  1.484429   1.335733
       comp           0.802036  0.732326  1.149397  3.473283  25.565922
       comprehension  1.463503  1.568395  1.866441  4.421639  26.552276
       difference     1.413010  1.460863  1.587594  1.568571   1.569735
       in1d           0.818502  0.844374  0.994093  1.042360   1.076255
       isin           1.008874  0.879706  1.021712  1.001119   0.964327
       setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575
       setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425
ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888
       comprehension  0.777445  0.827151  1.108028  3.473164  25.528879
       difference     1.086859  1.081396  1.293132  1.173044   1.237613
       setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124
       setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910
ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754
       comprehension  0.697749  0.762556  1.215225  3.510226  25.041832
       difference     1.055099  1.010208  1.122005  1.119575   1.383065
       setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460
       setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537
slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091
       comprehension  0.856893  0.870365  1.290730  3.564219  26.208937
       difference     1.470095  1.747211  2.886581  2.254690   2.050536
       setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452
       setdifflst     0.833700  0.846652  1.013061  1.110352   1.287831

fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True)
for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]):
    ax = axes[i // 2, i % 2]
    g.plot.bar(ax=ax, title=n)
    ax.legend_.remove()
fig.tight_layout()

Jest to względne w stosunku do czasu potrzebnego do uruchomienia df.drop(dlst, 1, errors='ignore'). Wygląda na to, że po całym tym wysiłku poprawiamy wydajność tylko w niewielkim stopniu.

wprowadź opis zdjęcia tutaj

Jeśli to prawda, najlepsze rozwiązania wykorzystują reindexlub reindex_axiswłamują się list(set(df.columns.values.tolist()).difference(dlst)). Blisko druga i wciąż bardzo nieznacznie lepsza niż dropjest np.setdiff1d.

rs.idxmin().pipe(
    lambda x: pd.DataFrame(
        dict(idx=x.values, val=rs.lookup(x.values, x.index)),
        x.index
    )
)

                      idx       val
10     (ridx, setdifflst)  0.653431
30    (ridxa, setdifflst)  0.746143
100   (ridxa, setdifflst)  0.816207
300    (ridx, setdifflst)  0.780157
1000  (ridxa, setdifflst)  0.861622
piRSquared
źródło
2

Składnia kropkowa działa w JavaScript, ale nie w Pythonie.

  • Pyton: del df['column_name']
  • JavaScript: del df['column_name'] lub del df.column_name
Lekarz
źródło
2

Jeśli twoja oryginalna ramka danych dfnie jest zbyt duża, nie masz żadnych ograniczeń pamięci i potrzebujesz tylko kilku kolumn, możesz równie dobrze utworzyć nową ramkę danych tylko z potrzebnymi kolumnami:

new_df = df[['spam', 'sausage']]
ccpizza
źródło
2

Możemy usunąć lub usunąć określoną kolumnę lub zwiędłe kolumny metodą drop () .

Załóżmy, że df jest ramką danych.

Kolumna do usunięcia = kolumna 0

Kod:

df = df.drop(column0, axis=1)

Aby usunąć wiele kolumn col1, col2,. . . , coln, musimy wstawić wszystkie kolumny, które musiały zostać usunięte z listy. Następnie usuń je metodą drop ().

Kod:

df = df.drop([col1, col2, . . . , coln], axis=1)

Mam nadzieję, że byłoby to pomocne.

Littin Rajan
źródło
df = df.drop([col1, col2, . . . , coln], axis=1)to nie działa, jeśli podam nazwę zmiennej zamiast col1, col2 itd. Dostaję kolumnę błędu nie w osi, gdy jest zdecydowanie obecna. @ Littin Czy możesz pomóc?
RSM
1

Kolejny sposób usuwania kolumny w Pandas DataFrame

jeśli nie szukasz usuwania w miejscu, możesz utworzyć nową ramkę danych, określając kolumny za pomocą DataFrame(...)funkcji jako

my_dict = { 'name' : ['a','b','c','d'], 'age' : [10,20,25,22], 'designation' : ['CEO', 'VP', 'MD', 'CEO']}

df = pd.DataFrame(my_dict)

Utwórz nową ramkę danych jako

newdf = pd.DataFrame(df, columns=['name', 'age'])

Otrzymujesz wynik tak dobry, jak to, co dostajesz z del / drop

Daksh
źródło
1
Jest to technicznie poprawne, ale wydaje się głupie, że trzeba wymienić każdą kolumnę, aby zachować zamiast tylko jednej (lub kilku) kolumn, które chcesz usunąć.
cs95,