【问题标题】:Boolean subset with named index具有命名索引的布尔子集
【发布时间】:2019-06-01 15:48:49
【问题描述】:

我正在尝试使用布尔数组来对数据框进行子集化。这有效:

df = pd.DataFrame(
    [
        (0, 0, 1),
        (0, 1, 2),
        (0, 3, 20),
        (1, 0, 2),
        (1, 1, 1),
        (1, 2, 30),
    ],
    columns = ['s', 'j', 'q']
)

df[df['j'] == 0]
df.loc[df['j'] == 0]

但是,以下失败:

df.set_index('s')[df['j'] == 0]
df.set_index('s').loc[df['j'] == 0]

我得到 s 的每个实例都等于 0,而不是 j。我求助于查询(我的情况比字面上的j == 0更复杂,或者我会直接使用它):

df['sub'] = (df['j'] == 0)
df.query('sub')

有没有办法在不创建临时变量的情况下做到这一点?非常感谢! Python 3.7 和熊猫 0.23.4

编辑

我所做的问题是布尔系列和数据框具有不同的索引。下面的答案详细说明了解决它的几种方法,但我支持这两种方法中的任何一种:

df.set_index('s')[(df['j'] == 0).values]

或

df.set_index('s', inplace = True)
df[df['j'] == 0]

【问题讨论】:

  • df.set_index('s') 的目的是什么?您当前的解决方案似乎没有使用 s 作为索引,也不需要它。
  • @jpp 正如大多数人可能猜到的那样,在我无缘无故地对数据进行子集之后,我的代码并没有结束......

标签: python python-3.x pandas boolean


【解决方案1】:

不要在布尔运算之间重新设置索引。您的布尔系列基于原始索引来放置真值和假值,然后您不能在具有 不同 索引的数据帧上重新使用该系列,因为索引然后映射到不同的行通过那个新索引。

如果您必须创建具有不同索引的数据框,请在之后创建您的布尔数组,或者在具有相同索引的另一个数据框上创建。所以这行得通:

df.set_index('s')[df.set_index('s')['j'] == 0]
df.set_index('s').loc[df.set_index('s')['j'] == 0]

也一样

df_indexed_on_s = df.set_index('s')
df_indexed_on_s[df_indexed_on_s['j'] == 0]
df_indexed_on_s.loc[df_indexed_on_s['j'] == 0]

如果你必须内联,也许你想使用一个可调用的索引;传入[...] 索引操作的函数预计会返回一个布尔系列,因此您也可以使用它:

df.set_index('s')[lambda sdf: sdf['j'] == 0]
df.set_index('s').loc[lambda sdf: sdf['j'] == 0]

或者您可以使用DataFrame.query() 让 Pandas 为您评估以字符串形式表示的查询,以针对您的数据框:

df.set_index('s').query('j == 0')

在底层,附加到df.set_index('s') 的索引被迭代,并且该索引中的值与df['j'] == 0 系列的值进行检查,以查看应该选择哪些行。后面的系列仍然使用原始索引(编号为 0 - 6 的 RangeIndex),因此将数字 0 - 6 映射到 True 和 False 值,而 s 只有一个 Int64Index 索引和值0 和1。对于s 索引具有0 的行,(df['j'] == 0)[0] 结果为True,因此这些行被选中,而对于1,结果为False。

df_indexed_on_s[df_indexed_on_s['j'] == 0] 的布尔索引需要更多的工作,因为该索引是相同的基于s 的 Int64Index, and0` 映射到 3 个单独的布尔结果,因此 Pandas 知道使用的不仅仅是索引选择匹配的行。

【讨论】:

  • 那些也支持可调用对象:df.set_index('s')[lambda df: df['j'] == 0]
  • @ayhan:此时为 lambda 参数传入当前数据帧,是的。
  • 我还要指出版本df.set_index('s').query('j == 0'),它可以满足许多简单的索引需求。它不需要构造显式系列(使用顶级pd.eval)。
  • 如何与底层ndarray 对齐,因为.set_index 不会修改排序? df.set_index('s')[(df.j==0).values]?
  • @ALollz:更多的可能性,是的,传入一个 numpy 布尔数组是另一种选择。我认为我们应该停止列出更多选项。
猜你喜欢
  • 1970-01-01
  • 2021-12-06
  • 2014-02-03
  • 2017-02-27
  • 2022-07-07
  • 1970-01-01
  • 2016-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多