Eliminazione di più colonne in base ai nomi delle colonne in Pandas


94

Ho alcuni dati e quando li importa ottengo le seguenti colonne non necessarie Sto cercando un modo semplice per eliminarli tutti

   'Unnamed: 24', 'Unnamed: 25', 'Unnamed: 26', 'Unnamed: 27',
   'Unnamed: 28', 'Unnamed: 29', 'Unnamed: 30', 'Unnamed: 31',
   'Unnamed: 32', 'Unnamed: 33', 'Unnamed: 34', 'Unnamed: 35',
   'Unnamed: 36', 'Unnamed: 37', 'Unnamed: 38', 'Unnamed: 39',
   'Unnamed: 40', 'Unnamed: 41', 'Unnamed: 42', 'Unnamed: 43',
   'Unnamed: 44', 'Unnamed: 45', 'Unnamed: 46', 'Unnamed: 47',
   'Unnamed: 48', 'Unnamed: 49', 'Unnamed: 50', 'Unnamed: 51',
   'Unnamed: 52', 'Unnamed: 53', 'Unnamed: 54', 'Unnamed: 55',
   'Unnamed: 56', 'Unnamed: 57', 'Unnamed: 58', 'Unnamed: 59',
   'Unnamed: 60'

Sono indicizzati dall'indicizzazione 0, quindi ho provato qualcosa di simile

    df.drop(df.columns[[22, 23, 24, 25, 
    26, 27, 28, 29, 30, 31, 32 ,55]], axis=1, inplace=True)

Ma questo non è molto efficiente. Ho provato a scrivere alcuni cicli for, ma questo mi ha colpito come un cattivo comportamento dei Panda. Quindi pongo la domanda qui.

Ho visto alcuni esempi simili ( Elimina più colonne panda ) ma questo non risponde alla mia domanda.


2
Cosa intendi per efficiente? Funziona troppo lentamente? Se il tuo problema è che non desideri ottenere gli indici di tutte le colonne che desideri eliminare, tieni presente che puoi semplicemente fornire df.dropun elenco di nomi di colonne:df.drop(['Unnamed: 24', 'Unnamed: 25', ...], axis=1)
Carsten

Non sarebbe più semplice creare un sottoinsieme delle colonne di interesse: ovvero df = df[cols_of_interest], altrimenti potresti df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)
dividere

2
Intendevo inefficiente in termini di digitazione o "cattivo odore di codice"
Peadar Coyle

1
Potrebbe valere la pena notare che nella maggior parte dei casi è più facile mantenere le colonne che si desidera quindi eliminare quelle che non si desidera: df = df ['col_list']
sparrow

Risposte:


65

Non so cosa intendi per inefficiente ma se intendi in termini di digitazione potrebbe essere più semplice selezionare le colonne di interesse e riassegnarle al df:

df = df[cols_of_interest]

Dov'è cols_of_interestun elenco delle colonne che ti interessano.

Oppure puoi tagliare le colonne e passarlo a drop:

df.drop(df.ix[:,'Unnamed: 24':'Unnamed: 60'].head(0).columns, axis=1)

La chiamata a headseleziona solo 0 righe poiché siamo interessati solo ai nomi delle colonne anziché ai dati

aggiornare

Un altro metodo: sarebbe più semplice usare la maschera booleana da str.containse invertirla per mascherare le colonne:

In [2]:
df = pd.DataFrame(columns=['a','Unnamed: 1', 'Unnamed: 1','foo'])
df

Out[2]:
Empty DataFrame
Columns: [a, Unnamed: 1, Unnamed: 1, foo]
Index: []

In [4]:
~df.columns.str.contains('Unnamed:')

Out[4]:
array([ True, False, False,  True], dtype=bool)

In [5]:
df[df.columns[~df.columns.str.contains('Unnamed:')]]

Out[5]:
Empty DataFrame
Columns: [a, foo]
Index: []

Ricevo errori quando provo a fare ~ df.columns ... (TypeError: bad operand type for unary ~: 'str') or df.columns.str.contains ... (AttributeError: 'Index' object has no attribute 'str'). Qualche idea sul perché questo potrebbe essere?
Dai

@EdChum posso creare df = df [cols_of_interest] , dove cols_of_interest aggiunge un nome di colonna ogni volta che un ciclo for itera?

@Victor no se lo fai sovrascrivi il tuo dfcon la tua nuova colonna appendforse dovresti ma non capisco davvero la tua domanda, dovresti pubblicare una vera domanda su SO piuttosto che chiedere come commento perché è povero di forma su SO
EdChum

@EdChum hai perfettamente ragione. Ho creato la domanda e sto cercando di risolverla cercando diverse parti di SO. Ecco il link ! qualsiasi contributo aiuterà stackoverflow.com/questions/48923915/...

213

L'approccio di gran lunga più semplice è:

yourdf.drop(['columnheading1', 'columnheading2'], axis=1, inplace=True)

1
Ho usato questo formato in alcuni dei miei codici e ricevo un SettingWithCopyWarningavviso?
KillerSnail

2
@KillerSnail, si salva per ignorare. Per evitare errori, prova: df = df.drop (['colheading1', 'colheading2'], axis = 1)
Philipp Schwarz

5
Il termine axisspiegato: stackoverflow.com/questions/22149584/… . Essenzialmente, axis=0si dice che sia "per colonna" ed axis=1è "per riga".
Rohmer

5
E inplace=Truesignifica che DataFrameè stato modificato in posizione.
Rohmer

1
@Killernail se non vuoi l'avvertimento, falloyourdf = yourdf.drop(['columnheading1', 'columnheading2'], axis=1)
happy_sisyphus

41

Il mio preferito personale e più facile delle risposte che ho visto qui (per più colonne):

df.drop(df.columns[22:56], axis=1, inplace=True)

O creando un elenco per più colonne.

col = list(df.columns)[22:56]
df.drop(col, axis=1, inplace=1)

8
Questa dovrebbe essere la risposta. Più pulito, più facile da leggere, con sintassi di indicizzazione Panda nativa semplice.
Brent Faust

2
Questa risposta dovrebbe avere il segno di spunta verde accanto ad essa, non le altre.
Siavosh Mahboubian

1
Piccola correzione (a meno che non mi sbagli): il secondo blocco di codice dovrebbe avere "inplace = True" invece di "inplace = 1".
Thredolsen

20

Questo è probabilmente un buon modo per fare quello che vuoi. Eliminerà tutte le colonne che contengono "Senza nome" nell'intestazione.

for col in df.columns:
    if 'Unnamed' in col:
        del df[col]

questo for col in df.columns:può essere semplificato for col in df:, inoltre l'OP non ha indicato quale sia lo schema di denominazione per le altre colonne, potrebbero contenere tutte 'Senza nome', anche questo è inefficiente in quanto rimuove le colonne una alla volta
EdChum

Certamente non è efficiente, ma finché non stiamo lavorando su enormi dataframe non avrà un impatto significativo. Il vantaggio di questo metodo è che è semplice da ricordare e veloce da codificare, mentre la creazione di un elenco delle colonne che desideri mantenere può essere piuttosto dolorosa.
knightofni

Penso che questo sia probabilmente più performante su df grande perché non devi fare una copia locale coninplace = True
Matt

13

Puoi farlo in una riga e una volta:

df.drop([col for col in df.columns if "Unnamed" in col], axis=1, inplace=True)

Ciò comporta un minor spostamento / copia dell'oggetto rispetto alle soluzioni precedenti.


11

Non sono sicuro che questa soluzione sia stata menzionata da qualche parte, ma un modo per farlo è pandas.Index.difference.

>>> df = pd.DataFrame(columns=['A','B','C','D'])
>>> df
Empty DataFrame
Columns: [A, B, C, D]
Index: []
>>> to_remove = ['A','C']
>>> df = df[df.columns.difference(to_remove)]
>>> df
Empty DataFrame
Columns: [B, D]
Index: []

4

Puoi semplicemente passare i nomi delle colonne come un elenco specificando l'asse come 0 o 1

  • asse = 1: lungo le righe
  • asse = 0: lungo le colonne
  • Per impostazione predefinita, asse = 0

    data.drop(["Colname1","Colname2","Colname3","Colname4"],axis=1)


4

Semplice e facile. Rimuovi tutte le colonne dopo il 22.

df.drop(columns=df.columns[22:]) # love it

Per modificare dfin posizione, aggiungi la bandiera inplace=True, in modo chedf.drop(columns=df.columns[22:], inplace=True)
arilwan il

1

Quanto segue ha funzionato per me:

for col in df:
    if 'Unnamed' in col:
        #del df[col]
        print col
        try:
            df.drop(col, axis=1, inplace=True)
        except Exception:
            pass

0

df = df[[col for col in df.columns if not ('Unnamed' in col)]]


1
Questo è simile a quello di Peter tranne per il fatto che le colonne indesiderate vengono filtrate anziché eliminate.
Sarah
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.