Присвоение pd.Series с помощью pd.IndexSlice приводит к значениям NaN, несмотря на совпадающие индексы - PullRequest
6 голосов
/ 19 сентября 2019

У меня есть многоиндексный ряд, как показано ниже.

> data = [['a', 'X', 'u', 1], ['a', 'X', 'v', 2], ['b', 'Y', 'u', 4], ['a', 'Z', 'u', 20]]
> s = pd.DataFrame(data, columns='one two three four'.split()).set_index('one two three'.split()).four
> s
one  two  three
a    X    u         1
          v         2
b    Y    u         4
a    Z    u        20
Name: four, dtype: int64

Затем вторая серия только с индексами one и three:

>>> data2 = [['a', 'u', 3], ['a', 'v', -3]]
>>> s2 = pd.DataFrame(data2, columns='one three four'.split()).set_index('one three'.split()).four
>>> s2
one  three
a    u        3
     v       -3
Name: four, dtype: int64

Итак, насколькокак я вижу, s2 и s.loc[pd.IndexSlice[:, 'X', :]] индексируются одинаково.

Таким образом, я бы ожидал, что смогу сделать:

>>> s.loc[pd.IndexSlice[:, 'X', :]] = s2

, но при этом результат будет NaN значения:

>>> s
one  two  three
a    X    u         NaN
          v         NaN
b    Y    u         4.0
a    Z    u        20.0
Name: four, dtype: float64

Как правильно это сделать?

Ответы [ 2 ]

3 голосов
/ 19 сентября 2019

pandas Мультииндексы иногда немного глючат, и это похоже на одно из этих обстоятельств.Если вы измените s2.index для соответствия s.index, назначение сработает:

In [155]: s2.index = pd.MultiIndex.from_product([['a'], ['X'], ['u', 'v']], names=['one', 'two', 'three'])

In [156]: s2
Out[156]:
one  two  three
a    X    u        3
          v       -3
Name: four, dtype: int64

In [157]: s
Out[157]:
one  two  three
a    X    u         1
          v         2
b    Y    u         4
a    Z    u        20
Name: four, dtype: int64

In [158]: s.loc[:, 'X', :] = s2

In [159]: s
Out[159]:
one  two  three
a    X    u         3
          v        -3
b    Y    u         4
a    Z    u        20
Name: four, dtype: int64

Вероятно, стоит поискать похожие проблемы в https://github.com/pandas-dev/pandas/issues и добавить его как новое, если его там еще нет.

В то же время еще одним вариантом является использование .unstack() для изменения формы данных для выполнения назначения:

In [181]: s = s.unstack('two')

In [182]: s['X'].loc[s2.index] = s2

In [183]: s.stack().swaplevel(1,2).sort_index()
Out[183]:
one  two  three
a    X    u         3.0
          v        -3.0
     Z    u        20.0
b    Y    u         4.0
dtype: float64
0 голосов
/ 19 сентября 2019

В качестве альтернативы @randy вы можете преобразовать s2 в список, так что вам не нужно заботиться о сопоставлении индексов (но тогда это будет не join, а просто порядок сохранения назначения наобе стороны):

>>> s.loc[pd.IndexSlice[:, 'X', :]]=s2.to_list()
>>> s
one  two  three
a    X    u         3.0
          v        -3.0
b    Y    u         4.0
a    Z    u        20.0
Name: four, dtype: float64
...