熊猫如何过滤系列


94

在执行groupby('name')并在其他列上使用过mean()函数后,我得到了这样的系列

name
383      3.000000
663      1.000000
726      1.000000
737      9.000000
833      8.166667

谁能告诉我如何过滤出平均值为1.000000的行?谢谢,我非常感谢您的帮助。


那么,如何在给定条件下过滤序列?

Answers:


127
In [5]:

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s = s[s != 1]
s
Out[0]:
383    3.000000
737    9.000000
833    8.166667
dtype: float64

10
我更喜欢下面的答案,因为它们可以被链接(即无需定义s,然后在表达式中使用两次)。不过仅适用于熊猫0.18。
IanS

另请参见piRSquared的答案中的时序比较。
IanS

63

从熊猫版本0.18+开始,也可以如下进行过滤

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

pd.Series(test).where(lambda x : x!=1).dropna()

结帐:http : //pandas.pydata.org/pandas-docs/version/0.18.1/whatsnew.html#method-chaininng-improvements


3
方法链接好得多(让我想起了Spark。)
Dylan Hogg

是的,但是Spark在这种情况下做得更直观:它只是摆脱了与谓词不匹配的行,这意味着不使用“ .dropna()”部分,在我阅读文档之前,这对我来说显然是多余的。被那个咬了:D
弗洛伦特·莫尼

44

正如DACW指出的那样,pandas 0.18.1中有方法链上的改进,可以很好地满足您的需求。

.where您可以将函数传递给.loc索引器或系列索引器[],而不必使用,而避免调用.dropna

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.loc[lambda x : x!=1]

test[lambda x: x!=1]

DataFrame和NDFrame类支持类似的行为。


2
这是我最喜欢的答案,而且它似乎也是最快的,而且不影响numpy(请参阅时序比较)。
IanS

21

一种快速的方法是使用numpy切片基础数组进行重构。请参见下面的时序。

mask = s.values != 1
pd.Series(s.values[mask], s.index[mask])

0
383    3.000000
737    9.000000
833    8.166667
dtype: float64

天真的时机

在此处输入图片说明


,我喜欢你的方法,我想知道如果我有多重口罩怎么办。Thx
Menglong Li

1
@MenglongLi取决于,您应该提出一个问题。您很可能将它们与&组合在一起。mask = mask1&mask2
piRSquared '17

6

另一种方法是先转换为DataFrame并使用查询方法(假设您已安装numexpr):

import pandas as pd

test = {
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
}

s = pd.Series(test)
s.to_frame(name='x').query("x != 1")

我认为以字符串形式传递条件不是一个好主意
SzymonPajzert

1
这增加了数据帧的所有开销,并且将非常慢。
惊人的

5

如果您喜欢链式操作,还可以使用compress函数:

test = pd.Series({
383:    3.000000,
663:    1.000000,
726:    1.000000,
737:    9.000000,
833:    8.166667
})

test.compress(lambda x: x != 1)

# 383    3.000000
# 737    9.000000
# 833    8.166667
# dtype: float64

1

就我而言,我有一个熊猫系列,其值是字符元组

Out[67]
0    (H, H, H, H)
1    (H, H, H, T)
2    (H, H, T, H)
3    (H, H, T, T)
4    (H, T, H, H)

因此,我可以使用索引来过滤系列,但可以创建所需的索引apply。我的条件是“查找所有正好为'H'的元组”。

series_of_tuples[series_of_tuples.apply(lambda x: x.count('H')==1)]

我承认它不是“ chainable”的(即注意我重复series_of_tuples两次;您必须将任何临时序列存储到变量中,以便可以在其上调用apply(...))。

可能还有其他方法(除外.apply(...))可以按元素操作以生成布尔索引。

使用可链接函数的许多其他答案(包括已接受的答案),例如:

  • .compress()
  • .where()
  • .loc[]
  • []

这些接受适用于Series的可调用项(lambda),而不适用于这些系列中的单个

因此,当我尝试将上述条件/可调用/ lambda与任何可链接函数一起使用时,我的系列元组的行为很奇怪,例如.loc[]

series_of_tuples.loc[lambda x: x.count('H')==1]

产生错误:

KeyError:“ H级必须与名称相同(无)”

我很困惑,但是似乎正在使用Series.countseries_of_tuples.count(...)函数,这不是我想要的。

我承认替代数据结构可能更好:

  • 类别数据类型?
  • 一个数据框(元组的每个元素变为一列)
  • 一系列字符串(将元组串联在一起):

这将创建一系列字符串(即,通过串联元组;将元组中的字符连接到单个字符串上)

series_of_tuples.apply(''.join)

这样我就可以使用链式Series.str.count

series_of_tuples.apply(''.join).str.count('H')==1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.