获取pandas boolean series为True的索引列表

bihw5rsg  于 2023-06-28  发布在  其他
关注(0)|答案(4)|浏览(147)

我有一个pandas系列,包含boolean条目。我想得到一个索引列表,其中的值是True
例如,输入pd.Series([True, False, True, True, False, False, False, True])
应该产生输出[0,2,3,7]
我可以用列表理解来做,但是有没有更干净或更快的方法?

jpfvwuh4

jpfvwuh41#

使用布尔索引

>>> s = pd.Series([True, False, True, True, False, False, False, True])
>>> s[s].index
Int64Index([0, 2, 3, 7], dtype='int64')

如果需要一个np.array对象,则获取.values

>>> s[s].index.values
array([0, 2, 3, 7])

使用np.nonzero

>>> np.nonzero(s)
(array([0, 2, 3, 7]),)

使用np.flatnonzero

>>> np.flatnonzero(s)
array([0, 2, 3, 7])

使用np.where

>>> np.where(s)[0]
array([0, 2, 3, 7])

使用np.argwhere

>>> np.argwhere(s).ravel()
array([0, 2, 3, 7])

使用pd.Series.index

>>> s.index[s]
array([0, 2, 3, 7])

使用Python内置的filter

>>> [*filter(s.get, s.index)]
[0, 2, 3, 7]

使用列表解析

>>> [i for i in s.index if s[i]]
[0, 2, 3, 7]
vd2z7a6w

vd2z7a6w2#

作为rafaelc's answer的补充,下面是以下设置的相应时间(从最快到最慢

import numpy as np
import pandas as pd
s = pd.Series([x > 0.5 for x in np.random.random(size=1000)])

使用np.where

>>> timeit np.where(s)[0]
12.7 µs ± 77.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

使用np.flatnonzero

>>> timeit np.flatnonzero(s)
18 µs ± 508 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

使用pd.Series.index

布尔索引的时间差真的让我感到惊讶,因为布尔索引通常更常用。

>>> timeit s.index[s]
82.2 µs ± 38.9 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

使用布尔索引

>>> timeit s[s].index
1.75 ms ± 2.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

如果需要np.array对象,请获取.values

>>> timeit s[s].index.values
1.76 ms ± 3.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

如果你需要一个稍微容易阅读的版本<--不是在原来的答案

>>> timeit s[s==True].index
1.89 ms ± 3.52 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

使用pd.Series.where <--不在原始答案中

>>> timeit s.where(s).dropna().index
2.22 ms ± 3.32 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> timeit s.where(s == True).dropna().index
2.37 ms ± 2.19 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

使用pd.Series.mask <--不在原始答案中

>>> timeit s.mask(s).dropna().index
2.29 ms ± 1.43 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> timeit s.mask(s == True).dropna().index
2.44 ms ± 5.82 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

使用列表解析

>>> timeit [i for i in s.index if s[i]]
13.7 ms ± 40.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

使用Python内置的filter

>>> timeit [*filter(s.get, s.index)]
14.2 ms ± 28.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

使用np.nonzero <--对我来说并不适用

>>> timeit np.nonzero(s)
ValueError: Length of passed values is 1, index implies 1000.

使用np.argwhere <--对我来说并不适用

>>> timeit np.argwhere(s).ravel()
ValueError: Length of passed values is 1, index implies 1000.
bxjv4tth

bxjv4tth3#

也可以使用:s.where(lambda x: x).dropna().index,它的优点是很容易链接管道-如果你的系列是在运行中计算的,你不需要将它分配给一个变量。
请注意,如果s是从r计算出来的:s = cond(r)也可以用途:r.where(lambda x: cond(x)).dropna().index

bqujaahr

bqujaahr4#

您可以使用pipeloc来链接操作,当s是中间结果并且您不想命名它时,这很有帮助。

s = pd.Series([True, False, True, True, False, False, False, True], index=list('ABCDEFGH'))

out = s.pipe(lambda s_: s_[s_].index)
# or
out = s.pipe(lambda s_: s_[s_]).index
# or
out = s.loc[lambda s_: s_].index
print(out)

Index(['A', 'C', 'D', 'H'], dtype='object')

相关问题