Löschen Sie die Spalte aus Pandas DataFrame mit del df.column_name

Beim Löschen einer Spalte in einem DataFrame verwende ich:

del df['column_name'] 

Und das funktioniert großartig. Warum kann ich Folgendes nicht verwenden?

 del df.column_name 

Da Sie auf die Spalte / Series als df.column_name , erwarte ich, dass dies funktioniert.

Es ist schwierig, del df.column_name einfach als Ergebnis von syntaktischen Einschränkungen in Python zu machen. del df[name] wird in df.__delitem__(name) unter die Deckblätter von Python übersetzt.

Der beste Weg, dies in Pandas zu tun, ist drop :

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

Dabei ist 1 die Achsennummer ( 0 für Zeilen und 1 für Spalten).

Um die Spalte zu löschen, ohne df neu df , können Sie df tun:

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

Um nach der Spaltennummer anstatt nach der Spaltenbezeichnung zu suchen, versuchen Sie dies zu löschen, zB die 1., 2. und 4. Spalte:

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

Benutzen:

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

Dadurch werden eine oder mehrere Spalten an Ort und Stelle gelöscht. Beachten Sie, dass inplace=True in Pandas v0.13 hinzugefügt wurde und in älteren Versionen nicht funktioniert. Sie müssten das Ergebnis in diesem Fall zurückgeben:

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

Drop-by-Index

Löschen Sie die erste, zweite und vierte Spalte:

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

Löschen Sie die erste Spalte:

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

Es gibt einen optionalen Parameter inplace so dass die Originaldaten geändert werden können, ohne eine Kopie zu erstellen.

Geklappt

Spaltenauswahl, Hinzufügen, Löschen

Spaltenspaltenname column-name :

 df.pop('column-name') 

Beispiele:

 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 

Die eigentliche Frage gestellt, von den meisten Antworten hier fehlt ist:

Warum kann ich del df.column_name nicht verwenden?

Zuerst müssen wir das Problem verstehen, was uns erfordert, in die Python-Magie-Methoden einzutauchen .

Wie Wes in seiner Antwort darauf hinweist, bildet del df['column'] die python- magische Methode df.__delitem__('column') die in Pandas implementiert ist, um die Spalte zu df.__delitem__('column')

Wie oben im Link zu python-magischen Methoden erwähnt :

In der Tat sollte del wegen der prekären Umstände, unter denen es aufgerufen wird, fast nie verwendet werden; Benutze es mit Vorsicht!

Sie könnten argumentieren, dass del df['column_name'] nicht verwendet oder del df.column_name sollte, und dabei sollte del df.column_name nicht einmal berücksichtigt werden.

del df.column_name könnte del df.column_name jedoch in pandas mit der magischen Methode __delattr__ . Dies führt jedoch zu bestimmten Problemen, die die del df['column_name'] Implementierung bereits hat, aber in geringerem Maße.

Beispiel Problem

Was passiert, wenn ich eine Spalte in einem Datenrahmen namens “dtypes” oder “columns” definiere.

Dann nehme ich an, dass ich diese Spalten löschen möchte.

del df.dtypes würde die Methode __delattr__ , als ob sie das Attribut “dtypes” oder die Spalte “dtypes” löschen müsste.

Architektonische Fragen hinter diesem Problem

  1. Ist ein Datenrahmen eine Sammlung von Spalten ?
  2. Ist ein Datenframe eine Sammlung von Zeilen ?
  3. Ist eine Spalte ein Attribut eines Datenrahmens?

Pandas antwortet:

  1. Ja, in jeder Hinsicht
  2. Nein, aber wenn Sie es möchten, können Sie die Methoden .ix , .loc oder .iloc verwenden.
  3. Vielleicht möchten Sie Daten lesen ? Dann ja , es sei denn, der Name des Attributs wird bereits von einem anderen zum Datenrahmen gehörenden Attribut übernommen. Möchten Sie Daten ändern ? Dann nein .

TLDR;

Du kannst del df.column_name nicht tun, weil Pandas eine ziemlich wild gewachsene Architektur hat, die neu überdacht werden muss, damit diese Art von kognitiver Dissonanz ihren Benutzern nicht del df.column_name .

Protip:

Verwenden Sie nicht df.column_name, es kann hübsch sein, aber es verursacht kognitive Dissonanz

Zen of Python zitiert das passt hier rein:

Es gibt mehrere Möglichkeiten, eine Spalte zu löschen.

Es sollte eine – und vorzugsweise nur eine – offensichtliche Möglichkeit geben, dies zu tun.

Spalten sind manchmal Attribute, aber manchmal nicht.

Sonderfälle sind nicht speziell genug, um die Regeln zu brechen.

Löscht del df.dtypes das dtypes-Attribut oder die dtypes-Spalte?

Angesichts der Mehrdeutigkeit, lehnen Sie die Versuchung ab zu erraten.

Eine nette Ergänzung ist die Möglichkeit, Spalten nur zu löschen, wenn sie existieren . Auf diese Weise können Sie mehr Anwendungsfälle abdecken und nur die vorhandenen Spalten aus den an sie übergebenen Labels löschen:

Einfach hinzufügen Fehler = ‘ignorieren’ , zum Beispiel .:

 df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore') 
  • Dies ist neu ab Pandas 0.16.1. Dokumentation ist hier .

Ab Version 0.16.1 können Sie tun

 df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore') 

Es empfiehlt sich, immer die [] -Notation zu verwenden. Ein Grund ist, dass die Attributnotation ( df.column_name ) nicht für nummerierte Indizes funktioniert:

 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 "", line 1 df.1 ^ SyntaxError: invalid syntax 

In Pandas 0.16.1+ können Sie Spalten nur dann löschen, wenn sie für die von @eiTanLaVi veröffentlichte Lösung existieren. Vor dieser Version können Sie dasselbe Ergebnis über ein bedingtes Listenverständnis erreichen:

 df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df], axis=1, inplace=True) 

TL; DR

Viel Aufwand, um eine marginal effizientere Lösung zu finden. Schwierig, die zusätzliche Komplexität zu rechtfertigen und gleichzeitig die Einfachheit von df.drop(dlst, 1, errors='ignore') opfern

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

Präambel
Das Löschen einer Spalte ist semantisch dasselbe wie das Auswählen der anderen Spalten. Ich werde ein paar zusätzliche Methoden zeigen.

Ich werde mich auch auf die allgemeine Lösung konzentrieren, mehrere Spalten gleichzeitig zu löschen und den Versuch zu ermöglichen, nicht vorhandene Spalten zu löschen.

Die Verwendung dieser Lösungen ist allgemein und wird auch für den einfachen Fall funktionieren.


Konfiguration
Betrachten Sie den pd.DataFrame df und die Liste, um dlst zu löschen

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

 df ABCDEFGHIJ 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'] 

Das Ergebnis sollte wie folgt aussehen:

 df.drop(dlst, 1, errors='ignore') ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Da ich das Löschen einer Spalte mit dem Auswählen der anderen Spalten gleichstelle, werde ich sie in zwei Typen aufteilen:

  1. Etikettenauswahl
  2. Boolesche Auswahl

Etikettenauswahl

Wir beginnen mit der Herstellung der Liste / des Arrays von Labels, die die Spalten darstellen, die wir behalten möchten, und ohne die Spalten, die wir löschen wollen.

  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'] 

Spalten von Labels
Um den Auswahlprozess zu vergleichen, nehmen wir an:

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

Dann können wir bewerten

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

Welche alle bewerten zu:

  ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Boolesches Slice

Wir können ein Array / eine Liste von booleschen Werten für das Slicing konstruieren

  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)

Spalten von Boolean
Zum Vergleich

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

Welche alle bewerten zu:

  ABCDEFG 0 1 2 3 4 5 6 7 1 1 2 3 4 5 6 7 2 1 2 3 4 5 6 7 

Robustes Timing

functionen

 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) 

Testen

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

Dies ist relativ zu der Zeit, die zum Ausführen von df.drop(dlst, 1, errors='ignore') . Es sieht so aus, als würden wir nach all dem Aufwand die performance nur moderat verbessern.

Bildbeschreibung hier eingeben

In der Tat verwenden die besten Lösungen reindex oder reindex_axis auf der Hack- list(set(df.columns.values.tolist()).difference(dlst)) . Eine nahe Sekunde und immer noch marginal besser als drop ist 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 

Pandas 0.21+ Antwort

Die Pandas-Version 0.21 hat die Drop-Methode leicht geändert, um sowohl den index als auch die reindex , dass sie der Signatur der rename und reindex Methoden entsprechen.

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

Persönlich bevorzuge ich die Verwendung des axis Parameters, um Spalten oder Indizes zu bezeichnen, da dies der vorherrschende Schlüsselwortparameter ist, der in fast allen Pandas-Methoden verwendet wird. Aber jetzt haben Sie einige Optionen in der Version 0.21.

Die Punktsyntax funktioniert in JavaScript, nicht jedoch in Python.

  • Python: del df['column_name']
  • JavaScript: del df['column_name'] oder del df.column_name