Использование str.contains в нескольких строках - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть датафрейм с пятью строками, который выглядит следующим образом:

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

Я пытаюсь найти все строки, которые содержат обе строки в любой комбинации столбцов - в данном случае, строки 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 голосов
/ 08 ноября 2018

Использование 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
0 голосов
/ 08 ноября 2018

Если есть только 2 слова, которые вы ищете, вы можете использовать np.isin и any, чтобы проверить, содержит ли каждая строка в базовом массиве 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
0 голосов
/ 08 ноября 2018

Если вы хотите, чтобы где-то были только строки с обоими словами word1 и word2, вам потребуется индекс stack, groupby и поиск внутри 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...