2015-11-11 2 views
7

Вот минимальный рабочий пример моей проблемы:Панды DataFrame содержит пренебрежимо малых после операции записи

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 

Почему первое задание неправильно? Кажется, что обе серии имеют одинаковый индекс, поэтому я предполагаю, что он должен привести к правильному результату.

Я использую pandas 0.17.0.

ответ

4

Когда вы пишете

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

и b является серия, индекс b должен точно соответствовать индексатор, порожденную a.loc[1,'b'] для того, чтобы значения в b быть скопирован в a. Оказывается, однако, что, когда a.columns является MultiIndex, the indexer for a.loc[1,'b'] является:

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

в то время как индекс для b является

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

Они не совпадают, и поэтому

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

Поскольку значения не выровнены, the code branch you fall into присваивает

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

Я нашел это, добавив pdb.set_trace() к коду:

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 

и просто шагая через него на «высоком уровне» и найти the problem occurs in

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

, а затем шагать через него снова (с более тонкой зубчатой ​​гребенкой) с точкой останова, начинающейся с линии, вызывающей self._align_series(indexer, value).


Обратите внимание, что при изменении индекса b также быть мультииндексным:

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

затем

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) 

дает

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

В моем случае 'b' на самом деле является временной серией, полученной нарезкой другого DataFrame (без MultiIndex). Есть ли способ решить эту проблему, не сохранив эту временную серию и переиндексируя ее? – MindV0rtex

+0

Я думаю, что самое легкое обходное решение - это тот, который вы показали - назначить неиндексированный объект: 'a.loc [1, 'b'] = b.values'. – unutbu

1

Вы можете напрямую назначить b в колонку в a, потому что b не является многоиндексной серией.Изменение b будет заставить его работать:

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) 

дает

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 

Другой случай, когда вы используете b.values, вероятно, работает, потому что панды принимает значения в b по номинальной стоимости, и пытается выполните самое логическое назначение для заданных значений.

Смежные вопросы