Ответ 1
Вы можете сделать это следующим образом:
df[(df['col_name'].str.contains('apple')) & (df['col_name'].str.contains('banana'))]
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 разных слов (виноград, арбуз, ягода, апельсин,... и т.д.)
Вы можете сделать это следующим образом:
df[(df['col_name'].str.contains('apple')) & (df['col_name'].str.contains('banana'))]
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
Вы также можете сделать это в стиле выражения регулярных выражений:
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)'
Затем вы можете делать свои вещи динамически.
Это работает
df.col.str.contains(r'(?=.*apple)(?=.*banana)',regex=True)
если вы хотите поймать в минимуме по крайней мере два слова в предложении, возможно, это сработает (принимая отзыв от @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
Попробуйте это регулярное выражение
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
Перечисление всех возможностей для больших списков громоздко. Лучше всего использовать 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
Если вы хотите использовать только собственные методы и избегать написания регулярных выражений, вот векторизованная версия без лямбда-выражений:
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]