2013-01-07 33 views
12

Sommario: Questo non funziona:intesa panda dataframe indicizzazione

df[df.key==1]['D'] = 1 

ma questo fa:

df.D[df.key==1] = 1 

Perché?

Riproduzione:

In [1]: import pandas as pd 

In [2]: from numpy.random import randn 

In [4]: df = pd.DataFrame(randn(6,3),columns=list('ABC')) 

In [5]: df 
Out[5]: 
      A   B   C 
0 1.438161 -0.210454 -1.983704 
1 -0.283780 -0.371773 0.017580 
2 0.552564 -0.610548 0.257276 
3 1.931332 0.649179 -1.349062 
4 1.656010 -1.373263 1.333079 
5 0.944862 -0.657849 1.526811 

In [6]: df['D']=0.0 

In [7]: df['key']=3*[1]+3*[2] 

In [8]: df 
Out[8]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 0 1 
1 -0.283780 -0.371773 0.017580 0 1 
2 0.552564 -0.610548 0.257276 0 1 
3 1.931332 0.649179 -1.349062 0 2 
4 1.656010 -1.373263 1.333079 0 2 
5 0.944862 -0.657849 1.526811 0 2 

Questo non funziona:

In [9]: df[df.key==1]['D'] = 1 

In [10]: df 
Out[10]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 0 1 
1 -0.283780 -0.371773 0.017580 0 1 
2 0.552564 -0.610548 0.257276 0 1 
3 1.931332 0.649179 -1.349062 0 2 
4 1.656010 -1.373263 1.333079 0 2 
5 0.944862 -0.657849 1.526811 0 2 

ma questo fa:

In [11]: df.D[df.key==1] = 3.4 

In [12]: df 
Out[12]: 
      A   B   C D key 
0 1.438161 -0.210454 -1.983704 3.4 1 
1 -0.283780 -0.371773 0.017580 3.4 1 
2 0.552564 -0.610548 0.257276 3.4 1 
3 1.931332 0.649179 -1.349062 0.0 2 
4 1.656010 -1.373263 1.333079 0.0 2 
5 0.944862 -0.657849 1.526811 0.0 2 

Link to notebook

La mia domanda è: Perché solo la 2 ° modo di lavorare? Non riesco a vedere una differenza nella logica di selezione/indicizzazione?

versione è 0.10.0

Edit: Questo non dovrebbe essere fatto in questo modo più. Da 0.11 c'è, vedi qui: http://pandas.pydata.org/pandas-docs/stable/indexing.html

+0

Come detto nelle risposte sembra essere un problema insensibile: dare un'occhiata a [questa domanda] (http://stackoverflow.com/q/9470604/1301710) per un problema simile. Non sono sicuro che si tratti di un problema di vista o di copia. – bmu

+0

Capisco ora che è chiaro (e in realtà semplicemente) la differenza tra la vista e la copia. Il primo metodo fornisce solo una copia che è garbage collection. Il secondo metodo fornisce una vista quindi l'impostazione viene eseguita nel dataframe originale. (vedi i commenti di Dougal sotto) –

risposta

15

La documentazione panda dice:

Restituzione di una vista rispetto a una copia

Le regole su quando viene restituita una vista sui dati sono interamente dipendenti da NumPy. Ogni volta che un array di etichette o un vettore booleano sono coinvolti nell'operazione di indicizzazione, il risultato sarà una copia. Con singola etichetta/indicizzazione scalare e affettatura, ad es. df.ix [3: 6] o df.ix [:, 'A'], verrà restituita una vista.

In df[df.key==1]['D'] prima volta che lo fanno per affettare booleana (che porta a una copia del dataframe), poi si sceglie una colonna [ 'D'].

In df.D[df.key==1] = 3.4, si seleziona prima una colonna, quindi si esegue il taglio booleano sulla serie risultante.

Questo sembra fare la differenza, anche se devo ammettere che è un po 'controintuitivo.

Edit: La differenza è stata identificata da Dougal, vedere il suo commento: Con la versione 1, la copia è fatto come il metodo __getitem__ viene chiamato per le operazioni di affettamento booleano. Per la versione 2, è possibile accedere solo al metodo __setitem__, quindi non restituire una copia ma solo assegnarla.

+0

Questo è quello che ho pensato anche io all'inizio, ma ci deve essere qualcos'altro in corso. 'df [df.key == 1] = 1000' assegna effettivamente 1000 a tutti i valori nella sezione, quindi non può essere una copia. Immagino che ci sia qualcosa di magico nei metodi __setattr__ o __setitem__. – cxrodgers

+1

ma siccome faccio un taglio booleano sulla serie risultante, dovrebbe essere anche una copia, non dovrebbe? Quindi, perché l'incarico funziona in questo modo? –

+0

Guarda il commento di Dougals sopra. Con la versione 1, la copia viene eseguita con il metodo __getitem __- per il taglio booleano. Per la versione 2, si accede solo al metodo __setitem __-, quindi non si restituisce una copia ma si assegna semplicemente. –

4

Sono quasi certo che il tuo primo modo restituisce una copia, invece di una vista, e quindi assegnarlo non cambia i dati originali. Non sono sicuro del perché questo sta accadendo però.

Sembra essere correlato all'ordine in cui si selezionano righe e colonne, NON la sintassi per ottenere colonne. Questi funzionano entrambi:

df.D[df.key == 1] = 1 
df['D'][df.key == 1] = 1 

E nessuno di questi lavori:

df[df.key == 1]['D'] = 1 
df[df.key == 1].D = 1 

Da questa evidenza, presumo che la fetta df[df.key == 1] sta tornando una copia. Ma questo non è il caso! df[df.key == 1] = 0 cambierà effettivamente i dati originali, come se fosse una vista.

Quindi, non sono sicuro. La mia sensazione è che questo comportamento sia cambiato con la versione dei panda. Mi sembra di ricordare che df.D usato per restituire una copia e df ['D'] usato per restituire una vista, ma questo non sembra essere più vero (panda 0.10.0).

Se si desidera una risposta più completa, si dovrebbe inserire nel forum pystatsmodels: https://groups.google.com/forum/?fromgroups#!forum/pystatsmodels

+3

'df [df.key == 1]' _does_ restituisce effettivamente una copia (come indica la risposta di Thorsten). La ragione per cui df [df.key == 1] = 0' modifica l'originale è che, sebbene la sintassi sia un po 'fuorviante, in realtà non sta affatto facendo la stessa cosa; la versione non assegnata chiama '__getitem__' e la versione di assegnazione' __setitem__'. È come se avessimo 'l = [0, 1, 2]', quindi 'l [1]' restituisce l'int 1 ma 'l [1] = 5' modifica l'originale. – Dougal