2015-11-11 11 views
7

Tutaj jest minimalny przykład mój problem robocza:Pandy DataFrame zawiera Nans po operacji zapisu

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 

Dlaczego pierwsze zadanie błędna? Obie Serie wydają się mieć ten sam indeks, więc zakładam, że powinien on dać prawidłowy wynik.

Używam pand 0.17.0.

Odpowiedz

4

Kiedy piszesz

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

i b to seria, indeks b musi dokładnie pasować do indeksowania generowane przez a.loc[1,'b'] celem dla wartości w b zostać skopiowany do a. Okazuje się jednak, że gdy a.columns jest MultiIndex, the indexer for a.loc[1,'b'] jest:

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

natomiast indeks b jest

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

Oni nie pasują do siebie, a zatem

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

Ponieważ wartości nie są wyrównane, the code branch you fall into przydziela

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

Znalazłem to dodając pdb.set_trace() do kodu:

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 

i po prostu stepping przez niego na "wysokim poziomie" i znalezienie the problem occurs in

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

a następnie wzmocnienie przez nią ponownie (z grzebieniem o drobniejszym uzębieniu) z punktem przerwania rozpoczynającym się na linii wywołującej self._align_series(indexer, value).


Zauważ, że jeśli zmieni indeks b być również MultiIndex:

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

następnie

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) 

daje

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

W moim przypadku 'b' jest w rzeczywistości tymczasową serią uzyskaną z cięcia innej ramki DataFrame (bez MultiIndex). Czy istnieje sposób rozwiązania tego problemu bez przechowywania tymczasowej serii i ponownego jej indeksowania? – MindV0rtex

+0

Myślę, że najłatwiejsze rozwiązanie to to, które pokazałeś - przypisz obiekt nieindeksowany: 'a.loc [1, 'b'] = b.values'. – unutbu

1

można bezpośrednio przypisać b do kolumny w a, ponieważ b nie jest serią wielu indeksu.Zmiana b uczyni to działa:

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) 

daje

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 

Drugi przypadek, gdy używasz b.values, prawdopodobnie działa ponieważ Pandy przyjmuje wartości w b w wartości nominalnej, i stara się wykonaj najbardziej logiczne przypisanie dla podanych wartości.