入门GPT(二)| 词袋模型(Bag of Words)辅助提升餐厅满意度

科技   2025-01-07 10:39   山西  

-推荐关注-

-正文-

Bag-of-Words 将文本看作由单词构成的无序集合,通过统计单词在文本中出现的频次来表示文本。因此,Bag-of-Words主要用于文本分类、情感分析、信息检索等自然语言处理任务中

  • 1. 什么是词袋模型(Bag of Words)
  • 2. 实现 Bag of Words 的步骤
    • 2.1 文本预处理
    • 2.2 构建词汇表
    • 2.3 向量化文本(词袋表示)
    • 2.4 通过文本的向量表示,使用余弦相似度分析句子相似度
  • 3. 统计词频,通过评论提升餐厅满意度

-- 领取学习资料大礼包,见文末

在自然语言处理领域,如何将人类语言转化为机器能够理解和处理的结构化数据,是解决文本问题的关键。

Bag of Words(简称 BoW)是一种经典的文本表示方法,凭借其简单性和易实现性,在文本分析中被广泛应用。从情感分析到文档分类,BoW 都扮演着重要角色

1. 什么是词袋模型(Bag of Words) 

Bag of Words 的核心思想是将文本看作一个“词袋”,不关注单词的顺序,仅统计每个单词在文本中出现的频率。它将一段文本转化为一个固定长度的向量,其中每个元素代表词汇表中一个单词的出现次数。虽然简单,但 BoW 能有效地将自然语言处理任务转化为标准的机器学习问题。


BoW 的特点是只关注词汇的频率,因此它特别适合于情感分析、文本分类、文档聚类等任务。然而,BoW 也有一些缺点,比如忽略了单词之间的顺序和上下文语义信息,这会导致对语义敏感的任务(如句子生成)性能不足。尽管如此,其简单高效的特性使其成为入门自然语言处理的理想方法。

2. 实现 Bag of Words 的步骤 

2.1 文本预处理

文本预处理是实现 BoW 的第一步。原始文本通常包含噪声,例如标点符号、停用词和大小写的混乱。清理文本能够减少噪声,提高模型的性能。对于中文,还需要进行分词,因为中文没有天然的单词分隔符。

以下是 Python 实现中文分词和停用词去除的代码:

"""
scikit-learn
"""

import jieba
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

# 客户评论
reviews = [
    "食物非常美味,配送速度也很快!",
    "配送太慢了,食物已经凉了。",
    "食物很棒,服务也不错,就是价格稍贵。",
    "从未见过这么差的服务,食物送得又慢又难吃!",
    "这家餐厅的食物真是太美味了,值得推荐!",
    "虽然配送慢,但食物的味道让我感到惊喜。",
    "食物美味可口,配送速度也有待提高。",
    "我觉得这道菜非常美味,值得再点一次。",
    "配送速度慢得让人失望,但食物的味道弥补了这一点。",
    "这道菜的味道真是美味无比,令人回味无穷。",
    "虽然等了很久,但食物的美味让我觉得值得。",
    "每次来这家店,食物的美味总是让我惊喜。",
    "配送的速度实在太慢,影响了我的用餐体验。"
]

# 分词预处理
# 停用词列表
stop_words = ["了""的""也""从未""这么""但""就是"]

# 分词与去停用词
def preprocess_text(corpus):
    processed_corpus = []
    for text in corpus:
        words = jieba.lcut(text)  # 使用 jieba 分词
        words = [word for word in words if word notin stop_words]  # 去停用词
        processed_corpus.append(" ".join(words))  # 拼接成字符串
    return processed_corpus

preprocessed_reviews = preprocess_text(reviews)
print("分词后的评论:")
print(preprocessed_reviews)

运行这段代码后,我们会得到预处理后的文本,如下所示:

分词后的评论:
['食物 非常 美味 , 配送 速度 很快 !''配送 太慢 , 食物 已经 凉 。''食物 很棒 , 服务 不错 , 价格 稍贵 。''从未见过 差 服务 , 食物 送得 又 慢 又 难吃 !''这家 餐厅 食物 真是太 美味 , 值得 推荐 !''虽然 配送 慢 , 食物 味道 让 我 感到 惊喜 。''食物 美味可口 , 配送 速度 有待 提高 。''我 觉得 这 道菜 非常 美味 , 值得 再点 一次 。''配送 速度慢 得 让 人 失望 , 食物 味道 弥补 这 一点 。''这 道菜 味道 真是 美味 无比 , 令人 回味无穷 。''虽然 等 很 久 , 食物 美味 让 我 觉得 值得 。''每次 来 这家 店 , 食物 美味 总是 让 我 惊喜 。''配送 速度 实在 太慢 , 影响 我 用餐 体验 。']

2.2 构建词汇表

接下来需要构建一个词汇表,包含所有预处理后的评论中出现的唯一单词。词汇表是向量化的基础,每个单词会被分配一个固定的索引。

以下是构建词汇表的代码:

from sklearn.feature_extraction.text import CountVectorizer

# 构建 BoW 模型
vectorizer = CountVectorizer()
bow_matrix = vectorizer.fit_transform(preprocessed_reviews)

# 输出词汇表
print("\n词汇表:")
print(vectorizer.get_feature_names_out())

结果中,vectorizer.get_feature_names_out() 会输出词汇表:

词汇表:
['一次''一点''不错''从未见过''令人''价格''体验''值得''再点''味道''回味无穷''太慢''失望''实在'
'已经''弥补''影响''很快''很棒''总是''惊喜''感到''推荐''提高''无比''有待''服务''每次'
'用餐''真是''真是太''稍贵''美味''美味可口''虽然''觉得''这家''送得''速度''速度慢''道菜''配送'
'难吃''非常''食物''餐厅']

2.3 向量化文本(词袋表示)

利用构建好的词汇表,我们可以将每条评论转化为一个稀疏向量。每个向量的长度等于词汇表的大小,每个元素代表该词汇在文本中出现的次数。

以下是生成 BoW 矩阵的代码:

# 输出 BoW 矩阵
print("\nBoW 矩阵:")
print(bow_matrix.toarray())

运行结果会生成一个稀疏矩阵,例如:

BoW 矩阵:
[[000000000000000001000000000000001000
0010010110]
 [000000000001001000000000000000000000
0000010010]
 [001001000000000000100000001000010000
0000000010]
 [000100000000000000000000001000000000
0100001010]
 [000000010000000000000010000000101000
1000000011]
 [000000000100000000001100000000000010
0000010010]
 [000000000000000000000001010000000100
0010010010]
 [100000011000000000000000000000001001
0000100100]
 [010000000100100100000000000000000000
0001010010]
 [000010000110000000000000100001001000
0000100000]
 [000000010000000000000000000000001011
0000000010]
 [000000000000000000011000000100001000
1000000010]
 [000000100001010010000000000010000000
0010010000]]

每一行是一个评论的 BoW 向量,每一列对应词汇表中的一个单词,元素值为该单词的出现次数。

2.4 通过文本的向量表示,使用余弦相似度分析句子相似度

余弦相似度是衡量两个向量之间夹角余弦值的指标,可以用于比较文本的内容相似程度

假设两个向量为 A 和 B,其余弦相似度定义为:

是两个向量的点积。

 和  分别是向量 A 和 B 的模(即欧几里得范数)。

余弦相似度的值在 [−1,1] 之间:

  • 1 表示两个向量方向完全一致(文本非常相似)。
  • 0 表示向量正交(无相似性)。
  • -1 表示两个向量方向完全相反(完全不相似)。

余弦相似度:人工智能小白到高手:余弦相似度(Cosine Similarity)的简单理解

from sklearn.metrics.pairwise import cosine_similarity
# 计算余弦相似度
cos_sim_matrix = cosine_similarity(bow_matrix)
# 热力图的绘制
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False# 解决负号显示问题

plt.figure(figsize=(1210))
sns.heatmap(cos_sim_matrix, annot=True, cmap='coolwarm'
            xticklabels=[reviews[i] for i in range(len(reviews))],
            yticklabels=[reviews[i] for i in range(len(reviews))], fmt=".2f"
            cbar_kws={"shrink".8})

plt.title("评论之间的余弦相似度热力图", fontsize=16)
plt.xlabel("评论", fontsize=14)
plt.ylabel("评论", fontsize=14)

# 调整标签的字体大小和旋转角度
plt.xticks(rotation=45, ha='right', fontsize=10)
plt.yticks(rotation=0, fontsize=10)
plt.tight_layout()
plt.show()

矩阵图中每个单元格表示两个句子之间的余弦相似度,颜色越深,句子在语义上越相似。

例如,“食物非常美味,配送速度也很快”和“食物美味可口,配送速度也有待提高”交叉处的单元格颜色相对较深,说明它们具有较高的余弦相似度0.50,这意味着它们在语义上较为相似。


通过余弦相似度矩阵,可以进行以下分析:

  • 找出最相似的评论对,例如通过矩阵中非对角线的最大值。
  • 为新评论寻找最相近的现有评论,作为推荐系统的一部分。
  • 根据相似度对评论进行聚类或分类。

3. 统计词频,通过评论提升餐厅满意度 

这些评论混合了正面和负面的反馈,统计矩阵中词频最高的词,可以分析客户关注的核心问题

# 计算词频
word_counts = np.asarray(bow_matrix.sum(axis=0)).flatten()
word_freq = dict(zip(vectorizer.get_feature_names_out(), word_counts))

# 按词频排序并输出前10个词
sorted_word_freq = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:10]

print("\n词频最高的前10个词:")
for word, freq in sorted_word_freq:
    print(f"{word}{freq}")

通过对生成的 BoW 矩阵计算词频,进行分析,我们可以发现一些有趣的现象。

例如,词汇“美味”、“值得”和“惊喜”在正面评论中出现频率较高,而“太慢”在负面评论中更常见。这些词的分布可以帮助我们快速定位客户满意和不满的关键点。正面评论中的高频词可能表明用户对食物质量满意,而负面评论中的词则表明配送慢是主要问题。

词频最高的前10个词:
食物: 10
美味: 6
配送: 6
值得: 3
味道: 3
速度: 3
太慢: 2
惊喜: 2
服务: 2
虽然: 2

词袋模型是早期的一种模型,相对简单,存在两个主要问题:

第一,它使用高维稀疏向量来表示文本,每个单词对应词汇表中的一个维度。这导致模型更适用于高维空间,而且计算效率低。

第二,词袋模型在表示单词时忽略了它们在文本中的上下文信息

Bag-of-Words 将文本看作由单词构成的无序集合,通过统计单词在文本中出现的频次来表示文本。因此,Bag-of-Words主要用于文本分类、情感分析、信息检索等自然语言处理任务中,在需要捕捉词序信息的任务中表现较差,如机器翻译和命名实体识别。





往日文章:

有需要的,在公众号「AI取经路」发消息「学习资料」即可获取。

--END--

点亮“赞”“在看”“分享”好友一起看


AI取经路
踏上取经路,比抵达灵山更重要! AI技术、 AI知识 、 AI应用 、 人工智能 、 大语言模型
 最新文章