#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