Pandas dataframe str.contains() И операция

df (Pandas Dataframe) имеет три строки.

some_col_name
"apple is delicious"
"banana is delicious"
"apple and banana both are delicious"

df.col_name.str.contains("apple|banana")

поймает все строки:

"apple is delicious",
"banana is delicious",
"apple and banana both are delicious".

Как применить оператор AND к методу str.contains, чтобы он захватывал только строки, содержащие BOTH apple и banana?

"apple and banana both are delicious"

Я хотел бы захватить строки, содержащие 10-20 разных слов (виноград, арбуз, ягода, апельсин,... и т.д.)

Ответ 1

Вы можете сделать это следующим образом:

df[(df['col_name'].str.contains('apple')) & (df['col_name'].str.contains('banana'))]

Ответ 2

df = pd.DataFrame({'col': ["apple is delicious",
                           "banana is delicious",
                           "apple and banana both are delicious"]})

targets = ['apple', 'banana']

# Any word from `targets` are present in sentence.
>>> df.col.apply(lambda sentence: any(word in sentence for word in targets))
0    True
1    True
2    True
Name: col, dtype: bool

# All words from `targets` are present in sentence.
>>> df.col.apply(lambda sentence: all(word in sentence for word in targets))
0    False
1    False
2     True
Name: col, dtype: bool

Ответ 3

Вы также можете сделать это в стиле выражения регулярных выражений:

df[df['col_name'].str.contains(r'^(?=.*apple)(?=.*banana)')]

Затем вы можете построить свой список слов в строке регулярных выражений так:

base = r'^{}'
expr = '(?=.*{})'
words = ['apple', 'banana', 'cat']  # example
base.format(''.join(expr.format(w) for w in words))

отобразит:

'^(?=.*apple)(?=.*banana)(?=.*cat)'

Затем вы можете делать свои вещи динамически.

Ответ 4

Это работает

df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)

Ответ 5

если вы хотите поймать в минимуме по крайней мере два слова в предложении, возможно, это сработает (принимая отзыв от @Alexander):

target=['apple','banana','grapes','orange']
connector_list=['and']
df[df.col.apply(lambda sentence: (any(word in sentence for word in target)) & (all(connector in sentence for connector in connector_list)))]

выход:

                                   col
2  apple and banana both are delicious

если у вас есть более двух слов для catch, которые разделены запятой ',', чем добавить его в список соединителей и изменить второе условие от всех к любому

df[df.col.apply(lambda sentence: (any(word in sentence for word in target)) & (any(connector in sentence for connector in connector_list)))]

выход:

                                        col
2        apple and banana both are delicious
3  orange,banana and apple all are delicious

Ответ 6

Попробуйте это регулярное выражение

apple.*banana|banana.*apple

Код:

import pandas as pd

df = pd.DataFrame([[1,"apple is delicious"],[2,"banana is delicious"],[3,"apple and banana both are delicious"]],columns=('ID','String_Col'))

print df[df['String_Col'].str.contains(r'apple.*banana|banana.*apple')]

Выход

   ID                           String_Col
2   3  apple and banana both are delicious

Ответ 7

Перечисление всех возможностей для больших списков громоздко. Лучше всего использовать reduce() и побитовый И оператор (&).

Например, рассмотрим следующий DataFrame:

df = pd.DataFrame({'col': ["apple is delicious",
                       "banana is delicious",
                       "apple and banana both are delicious",
                       "i love apple, banana, and strawberry"]})

#                                    col
#0                    apple is delicious
#1                   banana is delicious
#2   apple and banana both are delicious
#3  i love apple, banana, and strawberry

Предположим, что мы хотели выполнить поиск следующего:

targets = ['apple', 'banana', 'strawberry']

Мы можем сделать:

#from functools import reduce  # needed for python3
print(df[reduce(lambda a, b: a&b, (df['col'].str.contains(s) for s in targets))])

#                                    col
#3  i love apple, banana, and strawberry

Ответ 8

Если вы хотите использовать только собственные методы и избегать написания регулярных выражений, вот векторизованная версия без лямбда-выражений:

targets = ['apple', 'banana', 'strawberry']
fruit_masks = (df['col'].str.contains(string) for string in targets)
combined_mask = np.vstack(fruit_masks).all(axis=0)
df[combined_mask]