多列Pandas向量化字符串函数?

1 投票
3 回答
1043 浏览
提问于 2025-04-18 11:19

有没有办法在一个数据表(DataFrame)中查找包含某个字符串的行,不管这个字符串在哪一列?就像使用 Series.str 但适用于整个数据表那样?我现在有的代码是这样的:

In [2]: s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est"

In [3]: df = pd.DataFrame(np.array(s.split(' ')).reshape((-1, 4)), columns=['one', 'two', 'three', 'four'])

In [4]: df
Out[4]: 
           one            two         three        four
0        Lorem          ipsum         dolor         sit
1        amet,    consectetur   adipisicing       elit,
2          sed             do       eiusmod      tempor
3   incididunt             ut        labore          et
4       dolore          magna       aliqua.          Ut
5         enim             ad         minim     veniam,
6         quis        nostrud  exercitation     ullamco
7      laboris           nisi            ut     aliquip
8           ex             ea       commodo  consequat.
9         Duis           aute         irure       dolor
10          in  reprehenderit            in   voluptate
11       velit           esse        cillum      dolore
12          eu         fugiat         nulla   pariatur.
13   Excepteur           sint      occaecat   cupidatat
14         non      proident,          sunt          in
15       culpa            qui       officia    deserunt
16      mollit           anim            id         est

[17 rows x 4 columns]

In [5]: mask = df['one'].str.contains('dolor') | df['two'].str.contains('dolor') | df['three'].str.contains('dolor') | df['four'].str.contains('dolor')

In [6]: df[mask]
Out[6]: 
       one    two    three    four
0    Lorem  ipsum    dolor     sit
4   dolore  magna  aliqua.      Ut
9     Duis   aute    irure   dolor
11   velit   esse   cillum  dolore

[4 rows x 4 columns]

理想情况下,我想把最后两行替换成类似这样的东西:

df[df.ix[:, 'one':'four'].str.contains('dolor')]

这样做可以吗?

3 个回答

0

这段代码可以告诉你在任何一列中是否有“dolor”这个词:

df.ix[:, 'one':'four'].apply(lambda x: x.str.contains('dolor'), axis=1)

它会为每一行的每一列返回一个真或假的值。

如果你把这个和另一个操作结合起来,就能得到所有列的相关信息。

df.ix[:, 'one':'four'].apply(lambda x: x.str.contains('dolor'), axis=1).apply(lambda x: True in x.values, axis=1)

然后使用这个作为列的筛选条件,就能得到你的结果:

df[df.ix[:, 'one':'four'].apply(lambda x: x.str.contains('dolor'), axis=1).apply(lambda x: True in x.values, axis=1)]

不过这样做的速度大约慢了3到4倍 :( 比起其他的解决方案。

2

你可以使用 pd.np.char.array() 这个功能来进行向量化操作:

a = pd.np.char.array(df.values)
mask = a.find('dolor')!=-1
df2 = df.iloc[np.any(mask, axis=1)]

然后 df2 的内容将会是:

       one    two    three    four
0    Lorem  ipsum    dolor     sit
4   dolore  magna  aliqua.      Ut
9     Duis   aute    irure   dolor
11   velit   esse   cillum  dolore
1

Pandas 目前还没有 DataFrame.str 这种方法(至少现在还没有)。

不过,你可以使用

import numpy as np
mask = np.logical_or.reduce(
    [df[col].str.contains('dolor') 
     for col in df.loc[:, 'one':'four'].columns])

这样写会少一些代码,而且比

mask = df['one'].str.contains('dolor') | df['two'].str.contains('dolor') | df['three'].str.contains('dolor') | df['four'].str.contains('dolor')

要快一点。


In [29]: %timeit mask = np.logical_or.reduce([df[col].str.contains('dolor') for col in df.loc[:, 'one':'four'].columns]); df[mask]
1000 loops, best of 3: 761 µs per loop

In [30]: %timeit mask = df['one'].str.contains('dolor') | df['two'].str.contains('dolor') | df['three'].str.contains('dolor') | df['four'].str.contains('dolor'); df[mask]
1000 loops, best of 3: 1.13 ms per loop

撰写回答