在多行中使用str.contains

时间:2018-11-08 02:31:21

标签: python pandas

我有一个包含五行的数据框,如下所示:

index  col1   col2  col3   col4   col5
1      word1  None  word1  None   None
2      None   word1 word2  None   None
3      None   None  None   word2  word2
4      word1  word2 None   None   None

我正在尝试在 any 列组合中查找包含两个字符串的所有行-在这种情况下,是第2和4行。通常,我会使用str.contains方法按字符串过滤:

df[df['col1'].str.contains('word1 | word2'), case=False)

但是,这仅给我A)一列的结果,B)如果该列有一个单词,则为True。我凭直觉尝试过df[df[['col1', 'col2', 'col3', 'col4', 'col5']].str.contains('word1' & 'word2'), case=False),但是.str.contains在DataFrame对象上不起作用。

有没有一种方法可以不使用for循环?

3 个答案:

答案 0 :(得分:4)

使用any

s1=df.apply(lambda x : x.str.contains(r'word1')).any(1)
s2=df.apply(lambda x : x.str.contains(r'word2')).any(1)
df[s1&s2]
Out[452]: 
        col1   col2   col3  col4  col5
index                                 
2       None  word1  word2  None  None
4      word1  word2   None  None  None

答案 1 :(得分:4)

如果仅查找2个单词,则可以使用np.isinany来检查基础numpy数组中的每一行是否同时包含两个元素,请使用单独的每个单词isin

df[np.isin(df.values, 'word1').any(1) & np.isin(df.values, 'word2').any(1)]

   index   col1   col2   col3  col4  col5
1      2   None  word1  word2  None  None
3      4  word1  word2   None  None  None

或者,遵循相同的逻辑,但从@coldspeed的答案中借鉴了一点:

words = ['word1','word2']

df[np.logical_and.reduce([np.isin(df.values, w).any(1) for w in words])]

   index   col1   col2   col3  col4  col5
1      2   None  word1  word2  None  None
3      4  word1  word2   None  None  None

答案 2 :(得分:2)

假设只需要同时包含word1和word2的行,则需要stackgroupby索引并在apply内进行搜索。

words = ['word1', 'word2']
df[df.stack().groupby(level=0).apply(
    lambda x: all(x.str.contains(w, case=False).any() for w in words))]

print(df)
        col1   col2   col3  col4  col5
index                                 
2       None  word1  word2  None  None  # word1=>col2, word2=>col3
4      word1  word2   None  None  None  # word1=>col1, word2=>col2

另一种替代方法是使用np.logical_and.reduce

v = df.stack()
m = pd.Series(
        np.logical_and.reduce([
           v.str.contains(w, case=False).groupby(level=0).transform('any') 
           for w in words]),
        index=v.index)
df = df[m.unstack().all(1)]

print(df)
        col1   col2   col3  col4  col5
index                                 
2       None  word1  word2  None  None
4      word1  word2   None  None  None