在Pandas系列中使用in运算符

9

为什么我不能使用in来匹配Pandas系列中的字符串?在以下示例中,第一次评估结果出乎意料地为False,但第二次可以正常工作。

df = pd.DataFrame({'name': [ 'Adam', 'Ben', 'Chris' ]})
'Adam' in df['name']
'Adam' in list(df['name'])

1
df['name'].eq('Adam').any() - BENY
这就是 [mcve] 很有用的地方。目前为止,你的问题没有明确指定你是否希望 'Adam' <some operation> 'Adams'True。你是否想要一系列的 True/False 来表示每个元素的真实性? - piRSquared
2个回答

14

在第一个情况下:

因为in运算符被解释为调用df['name'].__contains__('Adam')。如果您查看pandas.Series__contains__的实现,您会发现它是以下内容(继承自pandas.core.generic.NDFrame):

def __contains__(self, key):
    """True if the key is in the info axis"""
    return key in self._info_axis

因此,你第一次使用的in被解释为:

'Adam' in df['name']._info_axis 

这会得到False,这是可预期的,因为df['name']._info_axis实际上包含有关range/index而不是数据本身的信息:

In [37]: df['name']._info_axis 
Out[37]: RangeIndex(start=0, stop=3, step=1)

In [38]: list(df['name']._info_axis) 
Out[38]: [0, 1, 2]
在第二种情况下:
'Adam' in list(df['name'])

使用listpandas.Series转换为值列表。因此,实际操作是:

In [42]: list(df['name'])
Out[42]: ['Adam', 'Ben', 'Chris']

In [43]: 'Adam' in ['Adam', 'Ben', 'Chris']
Out[43]: True
以下是几种更常用的做法(附带速度):
In [56]: df.name.str.contains('Adam').any()
Out[56]: True

In [57]: timeit df.name.str.contains('Adam').any()
The slowest run took 6.25 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 144 µs per loop

In [58]: df.name.isin(['Adam']).any()
Out[58]: True

In [59]: timeit df.name.isin(['Adam']).any()
The slowest run took 5.13 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 191 µs per loop

In [60]: df.name.eq('Adam').any()
Out[60]: True

In [61]: timeit df.name.eq('Adam').any()
10000 loops, best of 3: 178 µs per loop

注意:@Wen 在上面的评论中也建议了最后一种方法。


感谢您详细的回复。有没有更符合习惯用语的方法来完成第二个任务? - ceiling cat
3
考虑到 list(series) 会产生一个列表,而 iter(series) 则会产生一个迭代器,为什么有人会认为 series.__contains__ 检查的是索引而不是值呢?这看起来是 Series API 的一个重大缺陷。(感谢您提供的解释,我之前苦恼了很长时间才找到这个答案。) - BallpointBen
3
这个答案完全错误。(至少在使用Pandas 0.25.3版本时是这样的。)直接使用 'Adam' in df['name'].values 是可理解且高效的做法。 - Mr. Lance E Sloan
@Mr.LanceESloan 如果您不担心混淆DataFrame值,直接检查DataFrame值确实比列值更快,因为属性访问需要相当长的时间。 - Vovin

-1
found = df[df['Column'].str.contains('Text_to_search')]
print(len(found))

len(found)会给你列中匹配的数量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接