2015-11-11 22 views
7

Qui è un minimo esempio del mio problema di lavoro:Pandas dataframe contiene NaNs dopo un'operazione di scrittura

import pandas as pd 

columns = pd.MultiIndex.from_product([['a', 'b', 'c'], range(2)]) 
a = pd.DataFrame(0.0, index=range(3),columns=columns, dtype='float') 
b = pd.Series([13.0, 15.0]) 

a.loc[1,'b'] = b # this line results in NaNs 
a.loc[1,'b'] = b.values # this yields correct behavior 

Perché è la prima assegnazione errata? Entrambe le serie sembrano avere lo stesso indice, quindi presumo che dovrebbe produrre il risultato corretto.

Sto usando panda 0.17.0.

risposta

4

Quando si scrive

a.loc[1,'b'] = b 

e b è una serie, l'indice di b deve corrispondere esattamente l'indicizzatore generato da a.loc[1,'b'] in modo che i valori in b essere copiati nella a. Risulta, tuttavia, che quando è un a.columnsMultiIndex, the indexer for a.loc[1,'b'] è:

(Pdb) p new_ix 
Index([(u'b', 0), (u'b', 1)], dtype='object') 

mentre l'indice di b è

(Pdb) p ser.index 
Int64Index([0, 1], dtype='int64') 

Essi non corrispondono, e quindi

(Pdb) p ser.index.equals(new_ix) 
False 

Poiché i valori non sono allineati, the code branch you fall into assegna

(Pdb) p ser.reindex(new_ix).values 
array([ nan, nan]) 

ho trovato questo con l'aggiunta di pdb.set_trace() al codice:

import pandas as pd 

columns = pd.MultiIndex.from_product([['a', 'b', 'c'], range(2)]) 
a = pd.DataFrame(0.0, index=range(3),columns=columns, dtype='float') 
b = pd.Series([13.0, 15.0]) 
import pdb 
pdb.set_trace() 
a.loc[1,'b'] = b # this line results in NaNs 
a.loc[1,'b'] = b.values # this yields correct behavior 

e semplicemente fare un passo attraverso di essa ad un "alto livello" e trovare the problem occurs in

 if isinstance(value, ABCSeries): 
      value = self._align_series(indexer, value) 

e poi passando attraverso di nuovo (con un pettine a denti più fini) con un punto di rottura a partire dalla linea che chiama self._align_series(indexer, value).


Si noti che se si cambia l'indice di b di essere anche un MultiIndex:

b = pd.Series([13.0, 15.0], index=pd.MultiIndex.from_product([['b'], [0,1]])) 

poi

import pandas as pd 

columns = pd.MultiIndex.from_product([['a', 'b', 'c'], range(2)]) 
a = pd.DataFrame(0.0, index=range(3),columns=columns, dtype='float') 
b = pd.Series([13.0, 15.0], index=pd.MultiIndex.from_product([['b'], [0,1]])) 
a.loc[1,'b'] = b 
print(a) 

produce

a  b  c 
    0 1 0 1 0 1 
0 0 0 0 0 0 0 
1 0 0 13 15 0 0 
2 0 0 0 0 0 0 
+0

Nel mio caso, 'b' è in realtà una serie temporanea ottenuta dall'affettare un altro DataFrame (senza MultiIndex). C'è un modo per risolvere questo senza archiviare quella serie temporanea e reindicarla? – MindV0rtex

+0

Penso che la soluzione più semplice sia quella che hai mostrato - assegna un oggetto non indicizzato: 'a.loc [1, 'b'] = b.values'. – unutbu

1

È possibile assegnare direttamente b a una colonna in a, perché b non è una serie multiindice.La modifica b farà funzionare:

columns = pd.MultiIndex.from_product([['a', 'b', 'c'], range(2)]) 
a = pd.DataFrame(0.0, index=range(3),columns=columns, dtype='float') 
index = pd.MultiIndex.from_product([['b'], range(2)]) 
b = pd.Series([13.0, 15.0], index=index) 

a.loc[1,'b'] = b 
print(a) 

cede

a  b  c 
    0 1 0 1 0 1 
0 0 0 0 0 0 0 
1 0 0 13 15 0 0 
2 0 0 0 0 0 0 

L'altro caso, in cui si utilizza b.values, probabilmente funziona perché Panda assume i valori in b al valore nominale, e cerca di eseguire l'assegnazione più logica per i valori forniti.