与Pandas系列一起在运算符中使用

cei*_*cat 6 pandas

为什么我不能使用来匹配Pandas系列中的字符串in?在以下示例中,第一个评估意外导致False,但是第二个评估有效。

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

Moh*_*OUI 8

在第一种情况下:

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

def __contains__(self, key):
    """True if the key is in the info axis"""
    return key in self._info_axis
Run Code Online (Sandbox Code Playgroud)

因此,您的首次使用in被解释为:

'Adam' in df['name']._info_axis 
Run Code Online (Sandbox Code Playgroud)

这给了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]
Run Code Online (Sandbox Code Playgroud)

在第二种情况下:

'Adam' in list(df['name'])
Run Code Online (Sandbox Code Playgroud)

使用list,将转换pandas.Series为值列表。因此,实际操作是这样的:

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

In [43]: 'Adam' in ['Adam', 'Ben', 'Chris']
Out[43]: True
Run Code Online (Sandbox Code Playgroud)

以下是一些其他惯用的方法(以相关的速度)来完成您想要的事情:

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
Run Code Online (Sandbox Code Playgroud)

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

  • 鉴于 `list(series)` 生成其值的列表,并且 `iter(series)` 生成其值的迭代器,怎么可能有人期望 `series.__contains__` 检查 *index* 而不是值呢?似乎是 Series API 的一个主要缺陷。(但是谢谢你的解释,在找到这个答案之前我费了一番功夫)。 (4认同)
  • 这个答案是完全错误的。(至少在使用 Pandas 版本 0.25.3 时。)简单地在 df['name'].values 中使用 `'Adam' 是可以理解且高效的。 (3认同)