放置蒙版的熊猫多索引切片似乎不起作用

时间:2018-12-14 04:04:32

标签: pandas dataframe multi-index

我正在尝试在第二个(最内部)级别上获取Pandas 2级多索引数据帧的一部分,将一个蒙版应用于该片段,然后从原始数据帧中“放置”经过蒙版,切片的行为了避免链接分配问题,并确保将“ drop”操作应用于原始数据框,我将在一行代码中完成所有操作。

掩码是通过复杂的数学运算生成的,最终以与切片相同长度的布尔numpy数组的形式出现。

但是,当我在“放置”操作之后检查原始数据帧时,它仍然包含应该删除的数据。我浏览了许多页面以尝试解决此问题,并尝试对语法进行许多排列,但无济于事。

我没有收到有关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

现在尝试将行放到适当的位置。在这两种情况下,预期行都被删除:

>>> 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 :(得分:0)

我无法复制您的数据和预期的输出,但是我建议使用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对象)。