Bag-of-Words 模型

温馨提示:本文最后更新于2024-12-09 18:02:15,某些文章具有时效性,若有错误或已失效,请在下方留言

Bag-of-Words (BoW) 模型又称词袋模型。它将文本中的词看做是一个个独立的个体,不考虑它们在句子中的顺序,只关心每个词出现的频次。

词袋模型

词袋模型会将句子表示成向量,通过比较向量之间的相似度,就可以判断它们之间关联性的强弱。

计算文本相似度

词袋模型比较文本相似度的程序结构

构建语料库

定义一个简单的数据集,作为语料库。

# 构建数据集
corpos = [
    "我特别特别喜欢看电影",
    "这部电影真的是很好看的电影",
    "今天天气真好是难得的好天气",
    "我今天去看了一部电影",
    "电影院的电影都很好看"
]

给句子分词

jieba 包对这些句子进行分词。这个例子以词为单位处理语料,而不是

# 对句子进行分词
import jieba
# 使用 jieba.cut 进行分词,并将结果转换为列表,存储在 corpus_tokenized 中
corpus_tokenized = [list(jieba.cut(sentence)) for sentence in corpus

创建词汇表

根据分词结果,为语料库创建一个完整的词汇表,并显示这个词汇表。

# 创建词汇表
word_dict = {} # 初始化词汇表
# 遍历分词后的语料库
for sentence in corpus_tokenized:
    for word in sentence:
        # 如果词汇表中没有该词,则将其添加到词汇表中
        if word not in word_dict:
            # 分配当前词汇表索引
            word_dict[word] = len(word_dict)
# 打印词汇表
print("词汇表:", word_dict)

输出结果,如下所示

词汇表: {'我': 0, '特别': 1, '喜欢': 2, '看': 3, '电影': 4, '这部': 5, '真的': 6, '是': 7, '很': 8, '好看': 9, '的': 10, '今天天气': 11, '真好': 12, '难得': 13, '好': 14, '天气': 15, '今天': 16, '去': 17, '了': 18, '一部': 19, '电影院': 20, '都': 21}

生成词袋表示

根据这个词汇表将句子转换为词袋表示。

# 根据词汇表将句子转换为词袋表示
bow_vectors = [] # 初始化词袋表示
# 遍历分词后的语料库
for sentence in corpus_tokenized:
    # 初始化一个全0向量,其长度等于词汇表大小
    sentence_vector = [0] * len(word_dict)
    for word in sentence:
        # 给对应词索引位置上的数加1,表示该词在当前句子中出现了一次
        sentence_vector[word_dict[word]] += 1
    bow_vectors.append(sentence_vector)
print("词袋表示:", bow_vectors)

输出结果,如下所示

词袋表示: [[1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1]]

这里,我们得到了5个 Python 列表,分别对应语料库中的5句话。这5个列表,就是词袋表示向量,向量中的每个元素表示对应词在文本中出现的次数。向量的长度等于词汇表中的词的数量,这里我们一共有22个词。我们可以看到,词袋表示忽略了文本中词的顺序信息,仅关注词的出现频率。

例如,我们的词汇表为{’我’:0,’特别‘:1,’喜欢‘:2,’看’:3,’电影’:4},那么句子“我特别特别喜欢看电影”的词袋表示为[1,2,1,1,1],即“我”“喜欢”“看”和电影”这些词在句子中各出现了一次,而“特别”则出现了两次。

计算余弦相似度

计算余弦相似度(Cosine Similarity ),衡量两个文本向量的相似性。

余弦相似度可用来衡量两个向量的相似程度。它的值在-11之间,值越接近1,表示两个向量越相似;值越接近-1,表示两个向量越不相似;当值接近0时,表示两个向量之间没有明显的相似性。

余弦相似度计算公式如下

$$ cosine\_similarity(A, B) = (A \cdot B) / (\Vert A \Vert * \Vert B \Vert)$$

其中。\((A \cdot B)\) 表示向量 A 和向量 B 的点积,\(\Vert A \Vert\) 和 \(\Vert B \Vert\)表示向量 A 和向量 B 的范数(长度)。

编写函数计算余弦相似度,然后计算每两个句子之间的余弦相似度。

# 导入 numpy 库,用于计算余弦相似度
import numpy as np
# 定义余弦相似度函数
def cosine_similarity(vec1, vec2):
    # 计算向量 vec1 和 vec2 的点积
    dot_product = np.dot(vec1, vec2)
    # 计算向量 vec1 的范数
    norm_a = np.linalg.norm(vec1)
    # 计算向量 vec2 的范数
    norm_b = np.linalg.norm(vec2)
    # 返回余弦相似度
    return dot_product / (norm_a * norm_b)

# 初始化一个全0矩阵,用于存储余弦相似度
similarity_matrix = np.zeros((len(corpus), len(corpus)))
# 计算每两个句子之间的余弦相似度
for i in range(len(corpus)):
    for j in range(len(corpus)):
        similarity_matrix[i][j] = cosine_similarity(bow_vectors[i], bow_vectors[j])

可视化余弦相似度

使用 matplotlib 可视化句子和句子之间的相似度。

# 导入 matplotib 库,用于可视化余弦相似度矩阵
import matplotlib.pyplot as plt
# 用来设定字体样式
plt.rcParams['font.family'] = ['SimHei']
# 用来设定无衬线字体样式
plt.rcParams['font.sans-serif'] = ['SimHei']
# 用来正常显示负号
plt.rcParams['axes.unicode_minus'] = False
# 创建一个绘图对象
fig, ax = plt.subplots()
# 使用 matshow 函数绘制余弦相似度矩阵,颜色使用蓝色调
cax = ax.matshow(similarity_matrix, cmap=plt.cm.Blues)
# 条形图颜色映射
fig.colorbar(cax)
# x 轴刻度
ax.set_xticks(range(len(corpus)))
# y 轴刻度
ax.set_yticks(range(len(corpus)))
# 刻度标签
ax.set_xticklabels(corpus, rotation=45, ha='left')
# 刻度标签为原始句子
ax.set_yticklabels(corpus)
# 自动适应解决文字显示不全的问题
plt.tight_layout()
# 显示图形
plt.show()

输出结果,如下图所示

图片[3]-Bag-of-Words 模型-Stewed Noodles 资源

矩阵图中每个单元格表示两个句子之间的余弦相似度,颜色越深,句子在语义上越相似。例如,“这部电影真的是很好看的电影”和“电影院的电影都很好看”交叉处的单元格颜色相对较深,说明它们具有较高的余弦相似度,这意味着它们在语义上较为相似。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容