Я новичок в Python и nltk, поэтому был бы очень признателен за ваш вклад в решение следующей проблемы.
Цель:
Я хочу найти и подсчитать появление определенной терминологии в токенизированных предложениях, которые хранятся в pandas DataFrame. Термины, которые я ищу, хранятся в списке строк. Вывод следует сохранить в новом столбце.
Поскольку слова, которые я ищу, имеют грамматические наклонения (например, кошки вместо кошки), мне нужно решение, которое не только отображает точные совпадения. Я предполагаю, что выделение данных и поиск определенных основ было бы правильным подходом, но давайте предположим, что это не вариант, поскольку у нас все равно будут семантические совпадения.
Что я пробовал на данный момент:
Для дальнейшей обработки данных я предварительно обработал данные, выполнив следующие действия:
- Поместите все в нижний регистр
- Удалить знаки препинания
- Токенизация
- Удалить стоп-слова
Я попытался найти отдельные термины с помощью str.count('cat')
, но это не помогло, и данные были помечены как отсутствующие с помощью NaN
. Кроме того, я не знаю, как эффективно перебирать список слов для поиска при использовании pandas.
Мой код на данный момент:
import numpy as np
import pandas as pd
import re
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
# Function to remove punctuation
def remove_punctuation(text):
return re.sub(r'[^\w\s]','',text)
# Target data where strings should be searched and counted
data = {'txt_body': ['Ab likes dogs.', 'Bc likes cats.',
'De likes cats and dogs.', 'Fg likes cats, dogs and cows.',
'Hi has two grey cats, a brown cat and two dogs.']}
df = pd.DataFrame(data=data)
# Search words stored in a list of strings
search_words = ['dog', 'cat', 'cow']
# Store stopwords from nltk.corpus
stop_words = set(stopwords.words('english'))
# Data preprocessing
df['txt_body'] = df['txt_body'].apply(lambda x: x.lower())
df['txt_body'] = df['txt_body'].apply(remove_punctuation)
df['txt_body'] = df['txt_body'].fillna("").map(word_tokenize)
df['txt_body'] = df['txt_body'].apply(lambda x: [word for word in x if word not in stop_words])
# Here is the problem space
df['search_count'] = df['txt_body'].str.count('cat')
print(df.head())
Ожидаемый результат:
txt_body search_count
0 [ab, likes, dogs] 1
1 [bc, likes, cats] 1
2 [de, likes, cats, dogs] 2
3 [fg, likes, cats, dogs, cows] 3
4 [hi, two, grey, cats, brown, cat, two, dogs] 3
Хотите считать префиксы? В противном случае вам придется лемматизировать или выполнять некоторую обработку токенов … — person cru-436 schedule 15.12.2020
Привет! Да, было бы хорошо считать только части самого слова. Лемматизация — это небольшая проблема, поскольку я ищу решение, которое также можно было бы применить с неанглийским набором данных. Но стемминг не должен быть проблемой … Что бы вы посоветовали? — person cru-436 schedule 15.12.2020
Очень простое решение:
Затем вы можете решить, как определить функцию count_occurence. И, чтобы искать все search_words, что-то вроде этого сработает, хотя, вероятно, это не самый эффективный вариант:
Спасибо! Да, это работает для одной струны. Как бы вы перебрали строки в списке
search_words
и суммировали результаты для всех трех терминов? У меня проблемы с поиском подходящего решения. — person cru-436; 15.12.2020вы проверили мой отредактированный ответ? — person cru-436; 15.12.2020
Ах, прости. Я не обновлял страницу. Да, определенно работает. Спасибо еще раз! Вопрос об эффективности определенно актуален, поскольку я планирую применить его к довольно большому набору данных. Но предварительная обработка уже занимает некоторое время, так что пока все должно быть в порядке. Есть ли у вас догадки, как может выглядеть более эффективный подход? — person cru-436; 15.12.2020
Вероятно, это будет хорошо, если search_words не станет огромным. — person cru-436; 15.12.2020