如何(根据习惯)有效地从熊猫系列中提取元素

时间:2019-07-30 06:33:24

标签: python pandas

假设我有一个pandas Series对象,并且我想获取其相应值符合某些条件的所有元素(含义索引)。

有很多可能的方法可以实现,但是我希望这是一种简单,有效,惯用的方法-我还没有找到。

This question描述了如何使用布尔索引进行操作,但这对于一个简单的命令来说似乎太冗长了-例如:

import pandas as pd

age = pd.Series(index=['mom','dad','cat1','cat2','baby'],
                data=[30,30,3,3,1])

age[age>10].index.values

[编辑:请注意,变量名age在上一行中出现了两次。当然age[age>10]很短,但这仅仅是因为age是一个短名称-如果我遇到带有长名称的系列,例如age_of_family_members_after_filtering,那么{{1 }}看起来不太好。

我发现的其他解决方案也很冗长:

age_of_family_members_after_filtering[age_of_family_members_after_filtering>10]

或:

age.where(lambda x: x>10).dropna().index.values

(最后一个返回列表,而前一个返回数组,但是我都可以)

由于这是一个非常常见的命令,所以我期望像[name for name, _age in age.items() if _age>10] 之类的东西,而令我惊讶的是找不到它。

我想念什么(如果有的话)? 预先感谢。

4 个答案:

答案 0 :(得分:1)

对于给定的解决方案,您可以使用jupyter timeit magic命令进行简单的测试来进行评估:

# %%
%timeit age[age>10].index.values
--> 235 µs ± 8.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


# %%
%timeit age.where(lambda x: x>10).dropna().index.values
--> 510 µs ± 14.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# %%
%timeit [name for name, _age in age.items() if _age>10]
--> 12.5 µs ± 429 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

对于给定的解决方案,最后一个是最快的,但是第一个是最简单且仍然完全有效的解决方案。

另一个,请注意效率差异:

age.index[age.values > 10].tolist()
--> 16.5 µs ± 823 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

age.index[age > 10].tolist()
--> 157 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)


更新,带有@Alexander的想法:

# %% 
from itertools import compress
%timeit list(compress(age.index, age > 10))
--> 119 µs ± 3.24 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

答案 1 :(得分:1)

您可以压缩索引,但是我不认为它比简单的布尔索引更容易,IMO简洁。

from itertools import compress

>> list(compress(age.index, age > 10))
['mom', 'data']

答案 2 :(得分:1)

大熊猫中的行切片接受可调用对象。因此,您可以

age.loc[lambda x: x > 10]

对于这个小例子来说,看起来有点太多了,但是:

  • 如果系列名称不是age而是series_long_after_operation,这将变得更加清晰
  • 它支持方法链接,例如age.loc[lambda x: x > 10].loc[lambda x: x%2==0]

第二种方法实际上是进行长管道操作的方法,其中每种方法都返回不同的形状数据框。

答案 3 :(得分:0)

在搜索中,我发现对于一个数据框(尚无等效的序列),可以避免对变量名的重复调用,并且(同样,这可能是可读性问题-取决于编码约定,使用.query(可能比公认的解决方案性能差很多,但仍然需要注意:

import pandas as pd

df = pd.DataFrame(index=['mom','dad','cat1','cat2','baby'],
                data=[30,30,3,3,1],
               columns='age')

df.query('age>10')

结果

    age
mom 30
dad 30