pandas - 就地删除蒙面熊猫多索引切片似乎不起作用
问题描述
我正在尝试在第二个(最内层)级别获取 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() 在一行上的顺序应用将解决对原始数据帧的源数据的删除操作。
解决方案
我无法重现您的数据和预期输出,但我可以建议使用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 对象)。
推荐阅读
- git - 数据版本控制:管道参数中的绝对路径和项目路径?
- javascript - 全页站点:在每个循环中通过元素 onclick 导航
- python - 如何将变量 task_ids 传递给 Airflow 中的 xcom.pull?
- c# - 在 C# 中搜索二维对象数组
- discord - 是否可以通过命令显示我的 Discord 机器人当前连接了多少个语音通道?
- html - 如何显示淡入的svg元素?
- javascript - 滚动时突出显示菜单项不起作用
- haskell - 无法匹配预期类型 [Int] Haskell
- python - 使用 __new__ 无法执行的元类可以做什么?
- laravel - Laravel 8 的嵌套数据库播种