Elimina colonna da Panda DataFrame


1333

Quando si elimina una colonna in un DataFrame che uso:

del df['column_name']

E questo funziona alla grande. Perché non posso usare quanto segue?

del df.column_name

Dal momento che è possibile accedere alla colonna / serie come df.column_name, mi aspettavo che funzionasse.


2
Nota che questa domanda è in discussione su Meta .
RM

Risposte:


861

Come hai indovinato, la sintassi giusta è

del df['column_name']

È difficile far del df.column_namefunzionare semplicemente il risultato delle limitazioni sintattiche in Python. del df[name]viene tradotto in df.__delitem__(name)sotto le copertine da Python.


25
Mi rendo conto che si tratta di una "risposta" super vecchia, ma la mia curiosità è suscitata: perché è una limitazione sintattica di Python? class A(object): def __init__(self): self.var = 1crea una classe, quindi a = A(); del a.varfunziona bene ...
dwanderson,

14
@dwanderson la differenza è che quando una colonna deve essere rimossa, DataFrame deve avere una propria gestione per "come farlo". Nel caso di del df[name], viene tradotto in df.__delitem__(name)quale è un metodo che DataFrame può implementare e modificare in base alle sue esigenze. Nel caso di del df.name, la variabile membro viene rimossa senza possibilità di eseguire codice personalizzato. Considera il tuo esempio: puoi ottenere del a.varuna stampa di "eliminazione della variabile"? Se puoi, per favore dimmi come. Non posso :)
Yonatan il


5
Il commento di @Yonatan Eugene si applica anche a Python 2; i descrittori sono presenti in Python 2 dal 2.2 ed è banale soddisfare le tue esigenze;)
CS

1
Questa risposta non è davvero corretta - gli pandassviluppatori non lo hanno fatto , ma ciò non significa che sia difficile da fare.
wizzwizz4,

2186

Il modo migliore per farlo in Panda è usare drop:

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

dove si 1trova il numero dell'asse ( 0per righe e 1colonne).

Per eliminare la colonna senza dover riassegnare dfpuoi fare:

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

Infine, per rilasciare per numero di colonna anziché per etichetta di colonna , prova questo per eliminare, ad esempio la 1a, 2a e 4a colonna:

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

Lavorando anche con la sintassi "testo" per le colonne:

df.drop(['column_nameA', 'column_nameB'], axis=1, inplace=True)

79
È raccomandato delper qualche motivo?
Barba

20
Sebbene questo metodo di eliminazione abbia i suoi meriti, questa risposta non risponde realmente alla domanda posta.
Paolo,

109
True @Paul, ma a causa del titolo della domanda, la maggior parte delle persone che arrivano qui lo faranno cercando di capire come eliminare una colonna.
LondonRob,

24
@beardc un altro vantaggio di dropover delè che dropti consente di eliminare più colonne contemporaneamente, eseguire l'operazione sul posto o meno e anche eliminare i record lungo qualsiasi asse (utile specialmente per una matrice 3D o Panel)
piani cottura

8
Un altro vantaggio di dropover delè che drop fa parte dell'API di Panda e contiene documentazione.
Modulitos,

242

Uso:

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

Ciò eliminerà una o più colonne sul posto. Nota che è inplace=Truestato aggiunto in Panda v0.13 e non funzionerà con le versioni precedenti. In quel caso dovresti riassegnare il risultato:

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

3
Una nota su questa risposta: se viene usato un 'elenco', le parentesi quadre devono essere eliminate:df.drop(list,inplace=True,axis=1)
edesz,

1
questa dovrebbe davvero essere la risposta accettata, perché chiarisce la superiorità di questo metodo oltre del- può far cadere più di una colonna alla volta.
dbliss,

111

Drop per indice

Elimina la prima, la seconda e la quarta colonna:

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

Elimina la prima colonna:

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

C'è un parametro facoltativo in inplacemodo che i dati originali possano essere modificati senza creare una copia.

Popped

Selezione colonna, aggiunta, cancellazione

Elimina colonna column-name:

df.pop('column-name')

Esempi:

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

1
Come posso fare una fila in panda?
Kennet Celeste,

2
@Yugi Per questo puoi usare un frame di dati trasposto. ex - df.T.pop('A')
Clock Slave

@ClockSlave Che non modifica l'originale df. Si potrebbe fare df = df.T; df.pop(index); df = df.Tma questo sembra eccessivo.
cs95,

Invece di df.drop(df.columns[[0]], axis=1, inplace=True)non sarebbe abbastanza da usare df.drop([0], axis=1)?
Anirban Mukherjee il

1
@Anirban Mukherjee Dipende. Se vuoi eliminare il nome della colonna 0, allora df.drop(0, axis=1)funziona bene. Ma se non si conosce il nome della colonna e occorre rimuovere la prima colonna df.drop(df.columns[[0]], axis=1, inplace=True), è necessario selezionarla per posizione e rilasciarla.
jezrael,

71

La vera domanda posta, mancata dalla maggior parte delle risposte qui è:

Perché non posso usare del df.column_name?

All'inizio dobbiamo capire il problema, che ci richiede di immergerci nei metodi di magia del pitone .

Come sottolinea Wes nella sua risposta, del df['column']il metodo magico del pitone df.__delitem__('column')è implementato in Panda per eliminare la colonna

Tuttavia, come sottolineato nel link sopra sui metodi magici di Python :

In realtà, non __del__dovrebbe quasi mai essere usato a causa delle circostanze precarie in cui è chiamato; usalo con cautela!

Si potrebbe sostenere che del df['column_name']non dovrebbe essere usato o incoraggiato, e quindi del df.column_namenon dovrebbe nemmeno essere preso in considerazione.

Tuttavia, in teoria, del df.column_namepotrebbe essere implementato per lavorare in panda usando il metodo magico__delattr__ . Ciò tuttavia introduce alcuni problemi, problemi che l' del df['column_name']implementazione ha già, ma in misura minore.

Esempio di problema

E se definissi una colonna in un dataframe chiamato "dtypes" o "colonne".

Quindi supponiamo che io voglia eliminare queste colonne.

del df.dtypesrenderebbe il __delattr__metodo confuso come se dovesse eliminare l'attributo "dtypes" o la colonna "dtypes".

Domande architettoniche alla base di questo problema

  1. Un dataframe è una raccolta di colonne ?
  2. Un frame di dati è una raccolta di righe ?
  3. Una colonna è un attributo di un frame di dati?

Panda risponde:

  1. Sì, in tutti i modi
  2. No, ma se si vuole che sia, è possibile utilizzare i .ix, .loco .ilocmetodi.
  3. Forse, vuoi leggere i dati? Quindi , a meno che il nome dell'attributo non sia già assunto da un altro attributo appartenente al frame di dati. Vuoi modificare i dati? Quindi no .

TLDR;

Non si può fare del df.column_nameperché Panda ha un'architettura piuttosto selvaggia che deve essere riconsiderata affinché questo tipo di dissonanza cognitiva non si verifichi per i suoi utenti.

PROTIP:

Non usare df.column_name, potrebbe essere carino, ma provoca dissonanza cognitiva

Citazioni di Zen of Python che si adatta qui:

Esistono diversi modi per eliminare una colonna.

Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo.

Le colonne a volte sono attributi ma a volte no.

I casi speciali non sono abbastanza speciali da infrangere le regole.

Non del df.dtypeseliminare l'attributo dtypes o la colonna dtypes?

Di fronte all'ambiguità, rifiuta la tentazione di indovinare.


"In effetti, non __del__dovrebbe quasi mai essere usato a causa delle circostanze precarie in cui viene chiamato; usalo con cautela!" è completamente irrilevante qui, come è il metodo utilizzato qui __delattr__.
pepery il

1
@ppperry stai perdendo citazioni. si delintende il builtin, non il .__del__metodo di istanza. Il delbuiltin sta mappando __delattr__e su __delitem__questo sto costruendo il mio argomento. Quindi forse vuoi rileggere quello che ho scritto.
firelynx,

1
__... __viene interpretato come grassetto markup da StackExchange
pppery

2
"Non usare df.column_name, potrebbe essere carino, ma causa dissonanza cognitiva" Cosa significa? Non sono uno psicologo, quindi devo cercare questo per capire cosa intendi. Inoltre, citare The Zen non ha senso perché ci sono centinaia di modi validi per fare la stessa cosa nei panda.
cs95,

58

Una bella aggiunta è la possibilità di eliminare le colonne solo se esistono . In questo modo puoi coprire più casi d'uso e eliminerà solo le colonne esistenti dalle etichette passate ad esso:

Aggiungi semplicemente errori = 'ignora' , ad esempio .:

df.drop(['col_name_1', 'col_name_2', ..., 'col_name_N'], inplace=True, axis=1, errors='ignore')
  • Questo è nuovo da Panda 0.16.1 in poi. La documentazione è qui .

41

dalla versione 0.16.1 puoi farlo

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

3
E questo supporta anche il rilascio di più colonne, alcune delle quali non devono necessariamente esistere (cioè senza generare errori errors= 'ignore') df.drop(['column_1','column_2'], axis=1 , inplace=True,errors= 'ignore'), se si desidera un'applicazione del genere!
muone il

31

È buona norma utilizzare sempre la []notazione. Uno dei motivi è che la notazione dell'attributo ( df.column_name) non funziona per gli indici numerati:

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

26

Panda 0,21+ risposta

Pandas versione 0.21 ha cambiato il dropmetodo leggermente per includere sia le indexe columnsparametri per abbinare la firma del renamee reindexmetodi.

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

Personalmente, preferisco usare il axisparametro per indicare colonne o indice perché è il parametro della parola chiave predominante usato in quasi tutti i metodi di Panda. Ma ora hai alcune opzioni aggiunte nella versione 0.21.


1
df.drop (['column_a', 'column_c'], axis = 1) | per ora funziona per me
YouAreAwesome

21

In Panda 0.16.1+ è possibile eliminare le colonne solo se esistono per la soluzione pubblicata da @eiTanLaVi. Prima di quella versione, è possibile ottenere lo stesso risultato tramite una comprensione dell'elenco condizionale:

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

14

TL; DR

Un grande sforzo per trovare una soluzione leggermente più efficiente. Difficile giustificare la complessità aggiunta sacrificando la semplicità didf.drop(dlst, 1, errors='ignore')

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

Preambolo L'
eliminazione di una colonna equivale semanticamente alla selezione delle altre colonne. Mostrerò alcuni metodi aggiuntivi da considerare.

Mi concentrerò anche sulla soluzione generale di eliminare più colonne contemporaneamente e consentire il tentativo di eliminare le colonne non presenti.

L'uso di queste soluzioni è generale e funzionerà anche per il caso semplice.


Installazione
Considera l' pd.DataFrame dfelenco e da eliminaredlst

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

Il risultato dovrebbe apparire come:

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

Poiché sto equiparando l'eliminazione di una colonna alla selezione delle altre colonne, la suddividerò in due tipi:

  1. Selezione dell'etichetta
  2. Selezione booleana

Selezione dell'etichetta

Iniziamo producendo l'elenco / matrice di etichette che rappresentano le colonne che vogliamo mantenere e senza le colonne che vogliamo eliminare.

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

Colonne dalle etichette
Per confrontare il processo di selezione, supponiamo che:

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

Quindi possiamo valutare

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

Che tutti valutano per:

   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

Fetta Booleana

Possiamo costruire un array / elenco di booleani per lo slicing

  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)

Colonne booleane
Per motivi di confronto

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

Che tutti valutano per:

   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

Tempi solidi

funzioni

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)

analisi

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

Questo è relativo al tempo impiegato per l'esecuzione df.drop(dlst, 1, errors='ignore'). Sembra che dopo tutto questo sforzo, miglioriamo le prestazioni solo modestamente.

inserisci qui la descrizione dell'immagine

In realtà le migliori soluzioni utilizzano reindexo reindex_axissull'hacking list(set(df.columns.values.tolist()).difference(dlst)). Un secondo vicino e ancora marginalmente migliore di quello che dropè 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

2

La sintassi del punto funziona in JavaScript, ma non in Python.

  • Pitone: del df['column_name']
  • JavaScript: del df['column_name'] o del df.column_name

2

Se il tuo frame di dati originale dfnon è troppo grande, non hai vincoli di memoria e devi solo mantenere alcune colonne, potresti anche creare un nuovo frame di dati con solo le colonne necessarie:

new_df = df[['spam', 'sausage']]

2

Siamo in grado di rimuovere o eliminare una colonna specificata o colonne sprcified con il metodo drop () .

Supponiamo che df sia un frame di dati.

Colonna da rimuovere = colonna0

Codice:

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

Per rimuovere più colonne col1, col2,. . . , coln, dobbiamo inserire tutte le colonne che dovevano essere rimosse in un elenco. Quindi rimuoverli con il metodo drop ().

Codice:

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

Spero possa essere utile.


df = df.drop([col1, col2, . . . , coln], axis=1)questo non funziona se specifico un nome variabile al posto di col1, col2 ecc. Ottengo la colonna di errore non in asse quando è sicuramente presente. @Littin Puoi aiutarmi?
RSM,

1

Un altro modo di eliminare una colonna in Pandas DataFrame

se non stai cercando l'eliminazione sul posto, puoi creare un nuovo DataFrame specificando le colonne usando la DataFrame(...)funzione as

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

df = pd.DataFrame(my_dict)

Crea un nuovo DataFrame come

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

Ottieni un risultato buono come quello che ottieni con del / drop


1
Questo è tecnicamente corretto, ma sembra sciocco dover elencare ogni colonna da conservare anziché solo una (o poche) colonne che si desidera eliminare.
cs95,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.