我正在尝试使用布尔数组来子集数据帧。这有效:
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和pandas 0.23.4
编辑
我正在做的问题是布尔系列和数据框具有不同的索引。以下答案详细说明了解决该问题的几种方法,但我支持这两种方法之一:
df.set_index('s')[(df['j'] == 0).values]
或
df.set_index('s', inplace = True)
df[df['j'] == 0]
答案 0 :(得分:3)
不要在布尔操作之间重新设置索引。您的布尔系列基于原始索引来放置真值和假值,因此您不能在具有 different 索引的数据帧上重复使用该序列,因为索引随后映射到不同的行通过该新索引。
如果必须创建具有不同索引的数据框,请在执行此操作后在 上创建布尔数组,或者在具有相同索引的另一个数据框上创建。如此有效:
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}}索引。对于1
索引具有s
的行,0
的结果为(df['j'] == 0)[0]
,因此选择了这些行,而对于True
的结果为{{ 1}}。
1
的布尔索引需要更多的工作,因为那里的索引是相同的基于False
的Int64Index df_indexed_on_s[df_indexed_on_s['j'] == 0]
0`映射到3个单独的布尔结果,因此Pandas知道使用比索引更多的字符来选择匹配的行。