Come prendere sezioni di colonne di frame di dati in Panda


264

Carico alcuni dati di apprendimento automatico da un file CSV. Le prime 2 colonne sono osservazioni e le restanti colonne sono caratteristiche.

Attualmente, faccio quanto segue:

data = pandas.read_csv('mydata.csv')

che dà qualcosa del tipo:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))

Mi piacerebbe tagliare questo dataframe in due dataframes: uno contenente le colonne aed be uno contenente le colonne c, de e.

Non è possibile scrivere qualcosa del genere

observations = data[:'c']
features = data['c':]

Non sono sicuro di quale sia il metodo migliore. Ho bisogno di un pd.Panel?

A proposito, trovo che l'indicizzazione dei dataframe sia piuttosto incoerente: data['a']è consentita, ma data[0]non lo è. Dall'altro lato, data['a':]non è permesso ma lo data[0:]è. C'è una ragione pratica per questo? Questo è davvero confuso se le colonne sono indicizzate da Int, dato questodata[0] != data[0:1]


3
DataFrame è intrinsecamente un oggetto simile a una dict quando si esegue [...] df, tuttavia alcuni vantaggi, ad esempio df[5:10]sono stati aggiunti per la selezione di righe ( pandas.pydata.org/pandas-docs/stable/… )
Wes McKinney,

1
Quindi quale incoerenza è una decisione di progettazione a favore della convenienza? Va bene, ma deve essere sicuramente più esplicito per i principianti!
cpa,

3
La considerazione progettuale della convenienza a supporto rende la curva di apprendimento molto ripida. Vorrei che all'inizio ci fosse una migliore documentazione che presentasse un'interfaccia coerente. Ad esempio, concentrati solo sull'interfaccia ix.
Yu Shen,

Risposte:


243

Risposta 2017 - Panda 0.20: .ix è deprecato. Usa .loc

Vedi la deprecazione nei documenti

.locutilizza l'indicizzazione basata su etichette per selezionare sia righe che colonne. Le etichette sono i valori dell'indice o delle colonne. L'affettatura con .locinclude l'ultimo elemento.

Supponiamo che abbiamo un dataframe con le seguenti colonne:
foo, bar, quz, ant, cat, sat, dat.

# selects all rows and all columns beginning at 'foo' up to and including 'sat'
df.loc[:, 'foo':'sat']
# foo bar quz ant cat sat

.locaccetta la stessa notazione di slice che fanno gli elenchi Python sia per riga che per colonna. Slice notation beingstart:stop:step

# slice from 'foo' to 'cat' by every 2nd column
df.loc[:, 'foo':'cat':2]
# foo quz cat

# slice from the beginning to 'bar'
df.loc[:, :'bar']
# foo bar

# slice from 'quz' to the end by 3
df.loc[:, 'quz'::3]
# quz sat

# attempt from 'sat' to 'bar'
df.loc[:, 'sat':'bar']
# no columns returned

# slice from 'sat' to 'bar'
df.loc[:, 'sat':'bar':-1]
sat cat ant quz bar

# slice notation is syntatic sugar for the slice function
# slice from 'quz' to the end by 2 with slice function
df.loc[:, slice('quz',None, 2)]
# quz cat dat

# select specific columns with a list
# select columns foo, bar and dat
df.loc[:, ['foo','bar','dat']]
# foo bar dat

Puoi tagliare per righe e colonne. Per esempio, se si dispone di 5 file con le etichette v, w, x, y,z

# slice from 'w' to 'y' and 'foo' to 'ant' by 3
df.loc['w':'y', 'foo':'ant':3]
#    foo ant
# w
# x
# y

se il tuo utilizzo si applica con lambda row, come in: df['newcol'] = df.apply(lambda row: myfunc(row), axis=1) allora puoi in myfunc(row){... use row['foo':'ant']. ad esempio (in base a questa risposta StackOverflow ), all'interno myfuncdi puoi valutare se uno di questi non è numerico:row['foo':'ant'].apply(lambda x: isinstance(x, str)).any()
pashute

4
.ilocdovrebbe essere usato ora, invece di .loc. Risolvilo e lo voterò.
allungato il

1
@craned - che non è corretto. Dalla documentazione di Pandas: .loc è principalmente basato sull'etichetta, ma può anche essere usato con un array booleano. .loc genererà KeyError quando gli elementi non vengono trovati. Un'affermazione simile viene fatta riguardo a .iloc, ad eccezione del fatto che si riferisce specificamente all'affettatura basata sull'indice. In altre parole in questo esempio, ha usato l'indicizzazione basata su etichette e .loc è la scelta corretta (praticamente l'unica scelta). Se ad esempio si desidera eseguire una suddivisione in base alle posizioni 5:10, utilizzare .iloc
user2103050

149

Nota: .ix è stato deprecato a partire da Pandas v0.20. Dovresti invece usare .loco .iloc, a seconda dei casi.

L'indice DataFrame.ix è ciò a cui si desidera accedere. È un po 'confuso (sono d'accordo sul fatto che l'indicizzazione dei panda a volte è sconcertante!), Ma quanto segue sembra fare quello che vuoi:

>>> df = DataFrame(np.random.rand(4,5), columns = list('abcde'))
>>> df.ix[:,'b':]
      b         c         d         e
0  0.418762  0.042369  0.869203  0.972314
1  0.991058  0.510228  0.594784  0.534366
2  0.407472  0.259811  0.396664  0.894202
3  0.726168  0.139531  0.324932  0.906575

dove .ix [slice slice, column slice] è ciò che viene interpretato. Maggiori informazioni sull'indicizzazione di Panda qui: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-advanced


5
Attento che gli intervalli nei panda includano entrambi i punti finali, ovvero>>>data.ix[:, 'a':'c'] a b c 0 0.859192 0.881433 0.843624 1 0.744979 0.427986 0.177159
cavalletta

21
La cabina a più colonne può essere passata in questo mododf.ix[:,[0,3,4]]
user602599

3
@Karmel: sembra un errore di copia / incolla nell'output sopra. Forse intendevi df.ix[:,'b':'e']?
ChaimG,

6
E 'meglio usare local posto di ix: stackoverflow.com/a/31593712/4323
John Zwinck

5
Le vecchie risposte come questa devono essere eliminate. .ix è obsoleto e non deve mai essere utilizzato.
Ted Petrou,

75

Usiamo il set di dati titanico dal pacchetto seaborn come esempio

# Load dataset (pip install seaborn)
>> import seaborn.apionly as sns
>> titanic = sns.load_dataset('titanic')

usando i nomi delle colonne

>> titanic.loc[:,['sex','age','fare']]

usando gli indici di colonna

>> titanic.iloc[:,[2,3,6]]

utilizzando ix (versione precedente a Pandas <.20)

>> titanic.ix[:,[‘sex’,’age’,’fare’]]

o

>> titanic.ix[:,[2,3,6]]

usando il metodo reindex

>> titanic.reindex(columns=['sex','age','fare'])

6
In panda 0,20: .ixè deprecato.
Shihe Zhang,

avviso di deprecazione: Passing list-likes to .loc or [] with any missing label will raise KeyError in the future, you can use .reindex() as an alternative.quando si utilizzadf.loc[:, some_list_of_columns]
Marc Maxmeister

35

Inoltre, dato un DataFrame

dati

come nel tuo esempio, se desideri estrarre solo la colonna a e d (la prima e la quarta colonna), iloc mothod dal frame di dati panda è ciò di cui hai bisogno e potrebbe essere utilizzato in modo molto efficace. Tutto quello che devi sapere è l'indice delle colonne che desideri estrarre. Per esempio:

>>> data.iloc[:,[0,3]]

ti darà

          a         d
0  0.883283  0.100975
1  0.614313  0.221731
2  0.438963  0.224361
3  0.466078  0.703347
4  0.955285  0.114033
5  0.268443  0.416996
6  0.613241  0.327548
7  0.370784  0.359159
8  0.692708  0.659410
9  0.806624  0.875476

25

Puoi tagliare le colonne di una DataFramefacendo riferimento ai nomi di ciascuna colonna in un elenco, in questo modo:

data = pandas.DataFrame(np.random.rand(10,5), columns = list('abcde'))
data_ab = data[list('ab')]
data_cde = data[list('cde')]

Quindi, se voglio tutti i dati a partire dalla colonna 'b', devo trovare l'indice di 'b' in data.columns e fare data [data.columns [1:]]? Questo è il modo canonico di operare?
cpa,

1
Vuoi dire che vuoi selezionare tutte le colonne da 'b' in poi?
Brendan Wood,

Sì o selezionando tutte le colonne in un determinato intervallo.
cpa,

Sono abbastanza nuovo per i panda, quindi non posso parlare di ciò che è considerato canonico. Lo farei come hai detto tu, ma utilizzare la get_locfunzione su data.columnsper determinare l'indice della colonna 'b' o altro.
Brendan Wood,

20

E se sei venuto qui cercando di tagliare due gamme di colonne e combinarle insieme (come me), puoi fare qualcosa del genere

op = df[list(df.columns[0:899]) + list(df.columns[3593:])]
print op

Ciò creerà un nuovo frame di dati con le prime 900 colonne e (tutte) le colonne> 3593 (supponendo che nel set di dati siano presenti circa 4000 colonne).


Fantastico, qualcuno l'ha provato ... Mi stavo chiedendo, questo 0: 899 che ottiene le prime 900 colonne .. perché l'hanno fatto in questo modo? Non sembra affatto Python. Quando si usano intervalli in Python, è sempre "fino a" non "fino a quando e incluso"
zwep,

14

Ecco come è possibile utilizzare diversi metodi per eseguire il taglio di colonne selettivo, incluso il taglio di colonne selettivo basato su etichette, basato su indice e basato su intervalli selettivi.

In [37]: import pandas as pd    
In [38]: import numpy as np
In [43]: df = pd.DataFrame(np.random.rand(4,7), columns = list('abcdefg'))

In [44]: df
Out[44]: 
          a         b         c         d         e         f         g
0  0.409038  0.745497  0.890767  0.945890  0.014655  0.458070  0.786633
1  0.570642  0.181552  0.794599  0.036340  0.907011  0.655237  0.735268
2  0.568440  0.501638  0.186635  0.441445  0.703312  0.187447  0.604305
3  0.679125  0.642817  0.697628  0.391686  0.698381  0.936899  0.101806

In [45]: df.loc[:, ["a", "b", "c"]] ## label based selective column slicing 
Out[45]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [46]: df.loc[:, "a":"c"] ## label based column ranges slicing 
Out[46]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

In [47]: df.iloc[:, 0:3] ## index based column ranges slicing 
Out[47]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

### with 2 different column ranges, index based slicing: 
In [49]: df[df.columns[0:1].tolist() + df.columns[1:3].tolist()]
Out[49]: 
          a         b         c
0  0.409038  0.745497  0.890767
1  0.570642  0.181552  0.794599
2  0.568440  0.501638  0.186635
3  0.679125  0.642817  0.697628

Cerca di evitare di scaricare il codice come risposta e di spiegare cosa fa e perché. Il tuo codice potrebbe non essere ovvio per le persone che non hanno l'esperienza di programmazione pertinente. Modifica la tua risposta per includere chiarimenti, contesto e prova a menzionare eventuali limiti, ipotesi o semplificazioni nella tua risposta.
Sᴀᴍ Onᴇᴌᴀ,

1

È equivalente

 >>> print(df2.loc[140:160,['Relevance','Title']])
 >>> print(df2.ix[140:160,[3,7]])

1

se il frame di dati è simile al seguente:

group         name      count
fruit         apple     90
fruit         banana    150
fruit         orange    130
vegetable     broccoli  80
vegetable     kale      70
vegetable     lettuce   125

e OUTPUT potrebbe essere come

   group    name  count
0  fruit   apple     90
1  fruit  banana    150
2  fruit  orange    130

se si utilizza l'operatore logico np.logical_not

df[np.logical_not(df['group'] == 'vegetable')]

di più

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.logic.html

altri operatori logici

  1. logical_and (x1, x2, / [, out, where, ...]) Calcola il valore di verità di x1 AND x2 in termini di elementi.

  2. logical_or (x1, x2, / [, out, where, casting, ...]) Calcola il valore di verità di x1 OR x2 in termini di elementi.

  3. logical_not (x, / [, out, where, casting, ...]) Calcola il valore di verità di NOT x elemento-saggio.
  4. logical_xor (x1, x2, / [, out, where, ..]) Calcola il valore di verità di x1 XOR x2, dal punto di vista degli elementi.

0

Un altro modo per ottenere un sottoinsieme di colonne dal tuo DataFrame, supponendo che tu voglia tutte le righe, sarebbe quello di fare:
data[['a','b']]e data[['c','d','e']]
Se vuoi usare indici di colonne numerici puoi fare:
data[data.columns[:2]]edata[data.columns[2:]]

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.