Selezione di più colonne in un dataframe panda


1113

Ho dati in diverse colonne ma non so come estrarli per salvarli in un'altra variabile.

index  a   b   c
1      2   3   4
2      3   4   5

Come faccio a selezionare 'a', 'b'e salvarlo in a df1?

Provai

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

Nessuno sembra funzionare.


2
Non vuoi mai usarlo .ixperché è ambiguo. Utilizzare .iloco .locse è necessario.
Acumenus,

1
C'è un modo per farlo senza fare riferimento ai nomi delle intestazioni? come in R, posso farlo in questo modo: > csvtable_imp_1 <- csvtable_imp[0:6]e seleziona la quantità delta delle prime colonne tra 0 e 6. Tutto quello che dovevo fare è leggere la tabella csv come delimitata dalla libreria readr.
MichaelR

Ci ho lavorato un po 'di più. Ho trovato qualcosa che funzionava come desiderato. L'impostazione predefinita è selezionare numeri di caratteri e non colonne. infile_1 = largefile_stay.ix[:,0:6]
MichaelR

3
Per coloro che inciampano in questo ritardo, ixora è deprecato. Pandas consiglia di utilizzare: loc(indicizzazione basata sull'etichetta) o iloc(indicizzazione basata sulla posizione).
ZaydH,

Risposte:


1771

I nomi delle colonne (che sono stringhe) non possono essere suddivisi nel modo in cui hai provato.

Qui hai un paio di opzioni. Se conosci dal contesto quali variabili vuoi suddividere, puoi semplicemente restituire una vista di quelle colonne semplicemente passando un elenco nella __getitem__sintassi (le []).

df1 = df[['a','b']]

In alternativa, se è importante indicizzarli numericamente e non in base al loro nome (supponiamo che il tuo codice dovrebbe farlo automaticamente senza conoscere i nomi delle prime due colonne), puoi invece farlo:

df1 = df.iloc[:,0:2] # Remember that Python does not slice inclusive of the ending index.

Inoltre, dovresti familiarizzare con l'idea di una vista in un oggetto Pandas rispetto a una copia di tale oggetto. Il primo dei metodi precedenti restituirà una nuova copia in memoria dell'oggetto secondario desiderato (le sezioni desiderate).

A volte, tuttavia, ci sono convenzioni di indicizzazione in Panda che non lo fanno e invece ti danno una nuova variabile che si riferisce solo allo stesso pezzo di memoria dell'oggetto secondario o fetta dell'oggetto originale. Questo accadrà con il secondo modo di indicizzare, quindi puoi modificarlo con la copy()funzione per ottenere una copia regolare. Quando ciò accade, la modifica di ciò che si ritiene sia l'oggetto suddiviso a volte può alterare l'oggetto originale. Sempre bello essere alla ricerca di questo.

df1 = df.iloc[0,0:2].copy() # To avoid the case where changing df1 also changes df

Per utilizzare iloc, è necessario conoscere le posizioni (o gli indici) delle colonne. Poiché le posizioni delle colonne possono cambiare, anziché indici a codifica rigida, è possibile utilizzare ilocinsieme alla get_locfunzione del columnsmetodo dell'oggetto frame di dati per ottenere indici di colonna.

{df.columns.get_loc(c):c for idx, c in enumerate(df.columns)}

Ora puoi usare questo dizionario per accedere alle colonne attraverso i nomi e usando iloc.


192
Nota: df[['a','b']]produce una copia
Wes McKinney

1
Sì, questo era implicito nella mia risposta. La parte della copia era utile solo ix[]se si preferisce utilizzare ix[]per qualsiasi motivo.
ely,

1
ixindicizza le righe, non le colonne. Pensavo che l'OP volesse delle colonne.
Piani cottura

9
ixaccetta argomenti slice, quindi puoi anche ottenere colonne. Ad esempio, df.ix[0:2, 0:2]ottiene il sub-array 2x2 in alto a sinistra proprio come fa per una matrice NumPy (a seconda dei nomi delle colonne ovviamente). Puoi anche usare la sintassi della sezione sui nomi delle stringhe delle colonne, ad esempio df.ix[0, 'Col1':'Col5']. Che ottiene tutte le colonne che capita di essere ordinati tra le Col1e Col5nella df.columnsmatrice. Non è corretto affermare che ixindicizza le righe. Questo è solo il suo utilizzo più semplice. Supporta anche molto più indicizzazione di così. Quindi, ixè perfettamente generale per questa domanda.
ely,

7
@AndrewCassidy Non utilizzare mai più .ix. Se si desidera eseguire il taglio con numeri interi, utilizzare l' .ilocesclusiva dell'ultima posizione proprio come gli elenchi Python.
Ted Petrou,

133

A partire dalla versione 0.11.0, le colonne possono essere suddivise nel modo in cui hai provato a utilizzare l' .locindicizzatore:

df.loc[:, 'C':'E']

è equivalente a

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

e restituisce colonne Cattraverso E.


Una demo su un DataFrame generato casualmente:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)), 
                  columns=list('ABCDEF'), 
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out: 
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

Per ottenere le colonne da C a E (notare che a differenza della suddivisione in numeri interi, "E" è incluso nelle colonne):

df.loc[:, 'C':'E']

Out: 
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

Lo stesso vale per la selezione di righe in base alle etichette. Prendi le righe da 'R6' a 'R10' da quelle colonne:

df.loc['R6':'R10', 'C':'E']

Out: 
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.locaccetta anche un array booleano in modo da poter selezionare le colonne la cui voce corrispondente è nell'array True. Ad esempio, df.columns.isin(list('BCD'))restituisce array([False, True, True, True, False, False], dtype=bool)- Vero se il nome della colonna è nell'elenco ['B', 'C', 'D']; Falso, altrimenti.

df.loc[:, df.columns.isin(list('BCD'))]

Out: 
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...

110

Supponendo che i nomi delle colonne ( df.columns) siano ['index','a','b','c'], i dati desiderati si trovano nelle colonne 3a e 4a. Se non conosci i loro nomi durante l'esecuzione dello script, puoi farlo

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

Come sottolinea EMS nella sua risposta , df.ixsuddivide le colonne in modo un po 'più conciso, ma l' .columnsinterfaccia di slicing potrebbe essere più naturale perché utilizza la sintassi di indicizzazione / slicing dell'elenco python 1-D vanilla.

AVVERTENZA: 'index'è un nome errato per una DataFramecolonna. La stessa etichetta viene utilizzata anche per l' df.indexattributo reale , un Indexarray. Quindi la colonna viene restituita da df['index']e viene restituito l'indice DataFrame reale df.index. An Indexè un tipo speciale di Seriesottimizzato per la ricerca dei valori degli elementi. Per df.index è per cercare le righe in base alla loro etichetta. Questo df.columnsattributo è anche un pd.Indexarray, per cercare le colonne con le loro etichette.


3
Come ho notato nel mio commento sopra, non.ix è solo per le righe. È per affettare per scopi generici e può essere usato per affettare multidimensionale. Fondamentalmente è solo un'interfaccia per la solita sintassi di NumPy . Detto questo, puoi facilmente convertire un problema di suddivisione in colonne in un problema di suddivisione in righe semplicemente applicando un'operazione di trasposizione . Il tuo esempio usa , il che è un po 'fuorviante. Il risultato di è a ; fai attenzione a non trattarlo come un array. Inoltre, dovresti probabilmente cambiarlo in modo che corrisponda al tuo commento "3 ° e 4 °". __getitem__df.Tcolumns[1:3]columnsSeriescolumns[2:3]
ely,

@ Mr.F: il mio [2:4]è corretto. Hai [2:3]torto. E usare la notazione di python standard per generare una sequenza / serie non è fuorviante IMO. Ma mi piace il tuo bypass dell'interfaccia DataFrame per accedere all'array numpy sottostante con ix.
Piani cottura

In questo caso hai ragione, ma il punto che stavo cercando di sottolineare è che, in generale, il taglio con etichette in Pandas include l'endpoint della fetta (o almeno questo era il comportamento nella maggior parte delle versioni precedenti di Pandas). Quindi, se lo recuperi df.columnse vuoi dividerlo per etichetta , allora avresti una semantica della suddivisione diversa rispetto a se la suddividi per posizione dell'indice intero . Sicuramente non l'ho spiegato bene nel mio precedente commento.
ely,

Ahh, ora vedo il tuo punto. Ho dimenticato che si columnstratta di una serie immutabile e il getter è stato ignorato per utilizzare le etichette come indici. Grazie per il tempo dedicato a chiarire.
Piani cottura

2
Nota l'avvertimento di deprecazione: .ix è deprecato. Quindi questo ha senso: newdf = df [df.columns [2: 4]]
Martien Lubberink,

64
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5

1
E se volessi rinominare la colonna, ad esempio qualcosa del genere: df[['b as foo', 'c as bar']tale che l'output rinomina la colonna bcome fooe la colonna ccome bar?
kuanb

5
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
Greg,

62

Mi rendo conto che questa domanda è piuttosto vecchia, ma nell'ultima versione di Panda c'è un modo semplice per fare esattamente questo. I nomi delle colonne (che sono stringhe) possono essere suddivisi nel modo che preferisci.

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)

6
Questo può essere fatto solo alla creazione. La domanda è se lo hai già in un dataframe.
Banjocat,

3
@Banjocat, funziona con un dataframe esistente
mhery

23

È possibile fornire un elenco di colonne da eliminare e restituire DataFrame con solo le colonne necessarie utilizzando il drop() funzione su Pandas DataFrame.

Sto solo dicendo

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

restituirebbe un DataFrame con solo le colonne bec .

Il drop metodo è documentato qui .


23

Con i panda,

con i nomi delle colonne

dataframe[['column1','column2']]

per selezionare tramite iloc e colonne specifiche con numero indice:

dataframe.iloc[:,[1,2]]

con loc i nomi delle colonne possono essere usati come

dataframe.loc[:,['column1','column2']]

20

Ho trovato questo metodo molto utile:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

Maggiori dettagli possono essere trovati qui


Come prenderesti, diciamo, solo le colonne 2 e 5?
324

1
Quello sarebbe surveys_df.iloc [:, [2,5]]allora.
Julian Gorfer,

15

A partire da 0.21.0, l'utilizzo .loco []con un elenco con una o più etichette mancanti è deprecato a favore di .reindex. Quindi, la risposta alla tua domanda è:

df1 = df.reindex(columns=['b','c'])

Nelle versioni precedenti, l'utilizzo .loc[list-of-labels]avrebbe funzionato fintanto che fosse stata trovata almeno 1 chiave (altrimenti avrebbe sollevato a KeyError). Questo comportamento è obsoleto e ora mostra un messaggio di avviso. L'alternativa consigliata è usare .reindex().

Maggiori informazioni su Indicizzazione e selezione dei dati


10

Puoi usare i panda. Creo il DataFrame:

    import pandas as pd
    df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]], 
                      index=['Jane', 'Peter','Alex','Ann'],
                      columns=['Test_1', 'Test_2', 'Test_3'])

DataFrame:

           Test_1  Test_2  Test_3
    Jane        1       2       5
    Peter       5       4       5
    Alex        7       7       8
    Ann         7       6       9

Per selezionare 1 o più colonne per nome:

    df[['Test_1','Test_3']]

           Test_1  Test_3
    Jane        1       5
    Peter       5       5
    Alex        7       8
    Ann         7       9

Puoi anche usare:

    df.Test_2

E ottieni la colonna Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

Puoi anche selezionare colonne e righe da queste righe usando .loc(). Questo si chiama "affettare" . Si noti che prendo dalla colonna Test_1aTest_3

    df.loc[:,'Test_1':'Test_3']

La "Slice" è:

            Test_1  Test_2  Test_3
     Jane        1       2       5
     Peter       5       4       5
     Alex        7       7       8
     Ann         7       6       9

E se vuoi solo Petere Anndalle colonne Test_1e Test_3:

    df.loc[['Peter', 'Ann'],['Test_1','Test_3']]

Ottieni:

           Test_1  Test_3
    Peter       5       5
    Ann         7       9

8

Se vuoi ottenere un elemento per indice di riga e nome di colonna, puoi farlo proprio come df['b'][0] . È semplice come puoi immaginare.

Oppure puoi usare df.ix[0,'b'], uso misto di indice ed etichetta.

Nota: poiché v0.20 ixè stato deprecato a favore di loc/ iloc.


6

Un approccio diverso e semplice: iterare le righe

usando iterows

 df1= pd.DataFrame() #creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index,'A']=df.loc[index,'A']
    df1.loc[index,'B']=df.loc[index,'B']
    df1.head()

5
Si prega di non raccomandare l'uso di iterrows (). È un palese attivatore del peggior anti-modello nella storia dei panda.
cs95,

Potresti spiegare cosa intendi per "peggior anti-pattern"?
Ankita,

1
IMHO, iterrows () dovrebbe essere l'ultima opzione quando si usano i panda.
Elfo

5

I diversi approcci discussi nelle risposte di cui sopra si basano sul presupposto che l'utente sappia che gli indici di colonna devono essere eliminati o sottoposti a sottoinsiemi oppure l'utente desidera sottoinsiemi di un frame di dati utilizzando un intervallo di colonne (ad esempio tra "C": "E") . pandas.DataFrame.drop () è certamente un'opzione per sottoinsediare i dati in base a un elenco di colonne definite dall'utente (anche se devi essere cauto che usi sempre la copia di dataframe e i parametri inplace non dovrebbero essere impostati su True !!)

Un'altra opzione è utilizzare pandas.columns.difference () , che fa una differenza fissa sui nomi delle colonne e restituisce un tipo di indice di array contenente le colonne desiderate. Di seguito è la soluzione:

df = pd.DataFrame([[2,3,4],[3,4,5]],columns=['a','b','c'],index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

L'output sarebbe: b c 1 3 4 2 4 5


1
La copia () non è necessaria. cioè: df1 = df[df.columns.difference(columns_for_differencing)]restituirà un nuovo frame di dati / copiato. Sarai in grado di modificare df1senza alterare df. Grazie, a proposito. Questo era esattamente ciò di cui avevo bisogno.
Bazyli Debowski l'

4

puoi anche usare df.pop ()

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal 

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

fammi sapere se questo ti aiuta, per favore usa df.pop (c)


3

Ho visto diverse risposte su questo, ma su mi è rimasto poco chiaro. Come selezioneresti quelle colonne di interesse? La risposta è che se li hai raccolti in un elenco, puoi semplicemente fare riferimento alle colonne usando l'elenco.

Esempio

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

Ho la seguente lista / matrice numpy extracted_features, specificando 63 colonne. Il set di dati originale ha 103 colonne e vorrei estrarre esattamente quelle, quindi userei

dataset[extracted_features]

E finirai con questo

inserisci qui la descrizione dell'immagine

Questo qualcosa che useresti abbastanza spesso in Machine Learning (più specificamente, nella selezione delle funzionalità). Vorrei discutere anche di altri modi, ma penso che sia già stato coperto da altri stackoverflower. Spero che questo sia stato utile!


2

Puoi utilizzare il pandas.DataFrame.filtermetodo per filtrare o riordinare le colonne in questo modo:

df1 = df.filter(['a', 'b'])

0
df[['a','b']] # select all rows of 'a' and 'b'column 
df.loc[0:10, ['a','b']] # index 0 to 10 select column 'a' and 'b'
df.loc[0:10, ['a':'b']] # index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5] # index 0 to 10 and column 3 to 5
df.iloc[3, 3:5] # index 3 of column 3 to 5
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.