首页 > 解决方案 > Python根据另一个excel表中的关键词对excel中的数据进行分类

问题描述

我有两张 Excel 表格,一张有四种不同类型的类别,其中列出了关键字。我正在使用 Python 在评论数据中查找关键字并将它们与类别匹配。我曾尝试使用 pandas 和数据框进行比较,但我收到诸如“DataFrame 对象是可变的,因此它们不能被散列”之类的错误。我不确定是否有更好的方法,但我是 Pandas 的新手。

这是一个例子:

类别表

服务 经验
快速地 坏的
减缓 简单的

数据表

审查 # 地点 审查
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")

标签: pythonexcelpandasdataframe

解决方案


一种方法是从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.extractallaggregate进入摘要 +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或者,对于level=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

推荐阅读