Python классифицирует данные в Excel на основе ключевых слов из другого листа Excel

#python #excel #pandas #dataframe

Вопрос:

У меня есть два листа Excel, на одном есть четыре различных типа категорий с перечисленными ключевыми словами. Я использую Python, чтобы найти ключевые слова в данных обзора и сопоставить их с категорией. Я пробовал использовать панды и фреймы данных для сравнения, но получаю ошибки типа «Объекты фреймов данных изменчивы, поэтому их нельзя хэшировать». Я не уверен, что есть лучший способ, но я новичок в Пандах.

Вот пример:

Таблица категорий

Обслуживание Откройте для себя вики
быстрый плохой
медленный простой

спецификация

Обзор # Расположение Обзор
1 НЬЮ-ЙОРК «Обслуживание было быстрым!
2 Техас «В целом это был плохой опыт для меня»

В приведенных выше примерах я ожидал бы в результате следующего. Я ожидал бы, что отзыв 1 будет соответствовать категории обслуживания из-за слова «быстрый», и я ожидал бы, что отзыв 2 будет соответствовать категории обслуживания из-за слова «плохой». Я не ожидаю, что отзыв будет соответствовать каждому слову в таблице категорий, и это нормально, если один отзыв относится к нескольким категориям.

Вот мой код, обратите внимание, что я использую простой пример. В приведенном ниже примере я пытаюсь найти данные обзора, которые соответствовали бы списку ключевых слов Службы поддержки клиентов.

 import pandas as pd

# List of Categories
cat = pd.read_excel("Categories_List.xlsx")
# Data being used
data = pd.read_excel("Data.xlsx")

# Data Frame for review column
reviews = pd.DataFrame(data["reviews"])

# Data Frame for Categories
cs = pd.DataFrame(cat["Customer Service"])
be = pd.DataFrame(cat["Billing Experience"])
net = pd.DataFrame(cat["Network"])
out = pd.DataFrame(cat["Outcome"])

for i in reviews:
    if cs in reviews:
        print("True")
 

Ответ №1:

Одним из подходов было бы построение регулярного выражения из cat фрейма:

 exp = '|'.join([rf'(?P<{col}>{"|".join(cat[col].dropna())})' for col in cat])
 
 (?P<Service>fast|slow)|(?P<Experience>bad|easy)
 

cat В качестве альтернативы замените список столбцов для проверки:

 cols = ['Service']
exp = '|'.join([rf'(?P<{col}>{"|".join(cat[col].dropna())})' for col in cols])
 
 (?P<Service>fast|slow|quick)
 

Затем, чтобы получить совпадения, используйте str.extractall и aggregate в сводку join , чтобы добавить обратно в reviews кадр:

Объединены в список:

 reviews = reviews.join(
    reviews['Review'].str.extractall(exp).groupby(level=0).agg(
        lambda g: list(g.dropna()))
)
 
    Review #  Location                                  Review Service Experience
0         1  New York          The service was fast and easy!  [fast]     [easy]
1         2     Texas  Overall it was a bad experience for me      []      [bad]
 

Агрегируется в строку:

 reviews = reviews.join(
    reviews['Review'].str.extractall(exp).groupby(level=0).agg(
        lambda g: ', '.join(g.dropna()))
)
 
    Review #  Location                                  Review Service Experience
0         1  New York          The service was fast and easy!    fast       easy
1         2     Texas  Overall it was a bad experience for me                bad
 

В качестве альтернативы для теста на существование используйте any на уровне=0:

 reviews = reviews.join(
    reviews['Review'].str.extractall(exp).any(level=0)
)
 
    Review #  Location                                  Review  Service  Experience
0         1  New York          The service was fast and easy!     True        True
1         2     Texas  Overall it was a bad experience for me    False        True
 

Или итеративно по столбцам и с str.contains :

 cols = cat.columns
for col in cols:
    reviews[col] = reviews['Review'].str.contains('|'.join(cat[col].dropna()))
 
    Review #  Location                                  Review  Service  Experience
0         1  New York          The service was fast and easy!     True        True
1         2     Texas  Overall it was a bad experience for me    False        True