Отбрасывание мультииндексного фрагмента панд в масках не работает - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь взять срез двухуровневого мультииндексного фрейма данных Pandas на втором (самом внутреннем) уровне, применить маску к срезу и затем «отбросить» замаскированные, нарезанные строки из исходного фрейма данных.Я делаю все это в одной строке кода, чтобы попытаться избежать связанных цепных проблем присваивания и убедиться, что я применяю операцию «drop» к исходному фрейму данных.

Маска создается сложным математическимоперация и заканчивается в виде логического массива NUMPY той же длины, что и срез.

Однако, когда я проверяю исходный кадр данных после операции «drop», он все равно содержит данные, которые должны иметьЯ пропустил много страниц, чтобы попытаться решить эту проблему, и предпринял множество перестановок в синтаксисе, но безрезультатно.

Я не получаю предупреждений о SettingWithCopyWarning.

Следующий кодупрощенная модель моего кода, которая демонстрирует проблему и, надеюсь, сообщает, что я хочу сделать:

>>> import numpy as np
>>> import pandas as pd
>>> pd.__version__
u'0.23.4'
>>> index = pd.MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], 
                                  [u'one', u'two', u'three', u'four']], 
                          labels=[[0, 0, 1, 1, 2, 2, 3, 3], 
                                  [0, 0, 1, 1, 2, 2, 3, 3]], 
                          names=[u'first', u'second'])
>>> df = pd.DataFrame(np.random.randn(8, 4), index=index)
>>> df.columns = ['c0', 'c1', 'c2', 'c3']
>>> df
                    c0        c1        c2        c3
first second
bar   one    -2.366973 -0.887149 -0.301309  1.312207
      one     1.266500  0.864888 -1.407567  0.265077
baz   two    -1.926091 -0.671274 -0.295846  0.679759
      two    -0.212970  0.136552  0.219074  0.541827
foo   three  -0.698288 -2.059952  0.248811  0.947879
      three  -2.017481  0.163013 -0.906551 -0.102474
qux   four   -1.083530  0.097077  0.224977  0.251739
      four    0.943804  1.356789 -0.953357  0.592986

Создание маски из среза:

>>> two_data = df[df.index.get_level_values('second') == 'two']
>>> mask = (two_data['c1'] > 0)
>>> mask = mask.values
array([False,  True])

Продемонстрируйте, что удаление маскированных значений среза работает, когда не на месте (inplace = False):

>>> df[df.index.get_level_values('second') == 'two'][mask].drop('two', level=1)
Empty DataFrame
Columns: [c0, c1, c2, c3]
Index: []
>>> df[df.index.get_level_values('second') == 'two'].iloc[mask].drop('two', level=1)
Empty DataFrame
Columns: [c0, c1, c2, c3]
Index: []

Исходный кадр данных по-прежнему не поврежден, как и ожидалось:

>>> df
                    c0        c1        c2        c3
first second
bar   one    -2.366973 -0.887149 -0.301309  1.312207
      one     1.266500  0.864888 -1.407567  0.265077
baz   two    -1.926091 -0.671274 -0.295846  0.679759
      two    -0.212970  0.136552  0.219074  0.541827
foo   three  -0.698288 -2.059952  0.248811  0.947879
      three  -2.017481  0.163013 -0.906551 -0.102474
qux   four   -1.083530  0.097077  0.224977  0.251739
      four    0.943804  1.356789 -0.953357  0.592986

Теперь попытайтесь отбросить строки на месте.В обоих случаях ожидаемая строка NOT удалена:

>>> df[df.index.get_level_values('second') == 'two'][mask].drop('two', level=1, inplace=True)
>>> df
                    c0        c1        c2        c3
first second
bar   one    -2.366973 -0.887149 -0.301309  1.312207
      one     1.266500  0.864888 -1.407567  0.265077
baz   two    -1.926091 -0.671274 -0.295846  0.679759
      two    -0.212970  0.136552  0.219074  0.541827
foo   three  -0.698288 -2.059952  0.248811  0.947879
      three  -2.017481  0.163013 -0.906551 -0.102474
qux   four   -1.083530  0.097077  0.224977  0.251739
      four    0.943804  1.356789 -0.953357  0.592986

Попробуйте другую форму, используя iloc для маски, но безрезультатно:

>>> df[df.index.get_level_values('second') == 'two'].iloc[mask].drop('two', level=1, inplace=True)
>>> df
                    c0        c1        c2        c3
first second
bar   one    -2.366973 -0.887149 -0.301309  1.312207
      one     1.266500  0.864888 -1.407567  0.265077
baz   two    -1.926091 -0.671274 -0.295846  0.679759
      two    -0.212970  0.136552  0.219074  0.541827
foo   three  -0.698288 -2.059952  0.248811  0.947879
      three  -2.017481  0.163013 -0.906551 -0.102474
qux   four   -1.083530  0.097077  0.224977  0.251739
      four    0.943804  1.356789 -0.953357  0.592986

Ожидаемый результатесли бы у нас не работало на месте:

                    c0        c1        c2        c3
first second
bar   one    -2.366973 -0.887149 -0.301309  1.312207
      one     1.266500  0.864888 -1.407567  0.265077
baz   two    -1.926091 -0.671274 -0.295846  0.679759
foo   three  -0.698288 -2.059952  0.248811  0.947879
      three  -2.017481  0.163013 -0.906551 -0.102474
qux   four   -1.083530  0.097077  0.224977  0.251739
      four    0.943804  1.356789 -0.953357  0.592986

Пожалуйста, сообщите, как это должно быть сделано.Я ожидал, что это сработает, потому что я думал, что последовательное применение loc []. Iloc []. Drop () в одной строке будет обращаться к операции удаления к исходным данным исходного кадра данных.

1 Ответ

0 голосов
/ 14 декабря 2018

Я не могу воспроизвести ваши данные и ожидаемый вывод, но я могу предложить использовать eval и логическое индексирование:

df = df[~df.eval('second == "two" and c1 > 0')]

Или, используя query:

df = df.query('not (second == "two" and c1 > 0)')

Если вы делаете это немного по-другому, запрашивая индекс и отбрасывая его:

df = df.drop(df.query('second == "two" and c1 > 0').index)

Или

df.drop(df.query('second == "two" and c1 > 0').index, inplace=True)

Но имейте в виду, что оба эти метода (аналогичныМетоды выше) создаст копию вашего DataFrame.Невозможно сделать это на месте (даже inplace=True создает копию и присваивает ее исходному объекту DataFrame).

...