Python案例分析|文本相似度比较分析

简介: 本案例通过设计和实现有关文本相似度比较的类Vector和Sketch,帮助大家进一步掌握设计Python类来解决实际问题的能力。

image.png

01、文本相似度比较概述

通过计算并比较文档的摘要可实现文本的相似度比较。

文档摘要的最简单形式可以使用文档中的k-grams(k个连续字符)的相对频率的向量来表示。假设字符的取值可能有128种不同的值(ASCII码),则向量的维度d为128k,对于Unicode编码,这更是天文数字。因此,一般使用哈希函数hash(s) % d把k-grams字符串s映射到0到d-1之间的整数,从而使得文档摘要向量的维度为d。

创建文档摘要向量之后,可通过比较两个文档摘要向量的距离的方法来判断两个文档的相似度。

下面先阐述向量类(Vector)和文档摘要类(Sketch)的设计与实现,然后使用文档摘要类来比较文档的相似度。

02、向量(Vector)类设计和实现

向量是一种数学抽象,n维向量可以使用一个n个实数的有序列表(x0, x1, …, xn-1)。向量支持基本的四则算数运算,故可通过运算符重载来实现。

向量的基本运算包括:两个向量的加法、一个向量乘以一个标量(一个实数)、计算两个向量的点积、计算向量大小和方向。

(1)加法:x + y = ( x0 + y0, x1 + y1, . . ., xn-1 + yn-1 )

(2)减法:x - y = ( x0 - y0, x1 - y1, . . ., xn-1 - yn-1 )

(3)标量积:αx = (αx0, αx1, . . ., αxn-1)

(4)点积:x·y = x0y0 + x1y1 + . . . + xn-1yn-1

(5)大小:|x| = (x02 + x12 + . . . + xn-12)1/2

(6)方向:x / |x| = ( x0/|x|, x1/|x|, . . ., xn-1/|x|)

基本的向量(Vector)类设计思路如下。

(1)定义带一个列表参数(向量的坐标,可以是任意维度)的构造函数,用于初始化对应向量的实例对象属性_coords。

(2)重载方法getitem(),返回第i个元素,即第i维坐标。

(3)重载方法add()、sub()、abs(),实现向量的运算,即加法、减法、大小(模)。

(4)定义方法scale()、dot()、direction(),实现向量的运算,即标量积、点积、方向。

(5)重载方法len(),返回向量的维度。

(6)重载方法str(),返回向量的字符串表示。

基于上述设计思想,向量(Vector)的实现和测试代码如下所示。

【例1】向量类(Vector)的实现和测试(vector.py)。

import math
class Vector:
    """笛卡尔坐标系向量"""
    def __init__(self, a):
        """构造函数:切片拷贝列表参数a到对象实例变量_coords"""
        self._coords = a[:] # 坐标列表
        self._n = len(a) # 维度
    def __getitem__(self, i):
        """返回第i个元素,即第i维坐标"""
        return self._coords[i]
    def __add__(self, other):
        """返回2个向量之和"""
        result = []
        for i in range(self._n):
            result.append(self._coords[i] + other._coords[i])
        return Vector(result)
    def __sub__(self, other):
        """返回2个向量之差"""
        result = []
        for i in range(self._n):
            result.append(self._coords[i] - other._coords[i])
        return Vector(result)
    def scale(self, n):
        """返回向量与数值的乘积差"""
        result = []
        for i in range(self._n):
            result.append(self._coords[i] * n)
        return Vector(result)
    def dot(self, other):
        """返回2向量的内积"""
        result = 0
        for i in range(self._n):
            result += self._coords[i] * other._coords[i]
        return result
    def __abs__(self):
        """返回向量的模"""
        return math.sqrt(self.dot(self))
    def direction(self):
        """返回向量的单位向量"""
        return self.scale(1.0 / abs(self))
    def __str__(self):
        """返回向量的字符串表示"""
        return str(self._coords)
    def __len__(self):
        """返回向量的维度"""
        return self._n
#测试代码
def main():
    xCoords = [2.0, 2.0, 2.0]
    yCoords = [5.0, 5.0, 0.0]
    x = Vector(xCoords)
    y = Vector(yCoords)
    print('x = {}, y = {}'.format(x, y))
    print('x + y = {}'.format(x + y))
    print('10x = {}'.format(x.scale(10.0)))
    print('|x| = {}'.format(abs(x)))
    print(' = {}'.format(x.dot(y)))
    print('|x-y| = {}'.format(abs(x-y)))
if __name__ == '__main__': main()

程序运行结果如下。

x = [2.0, 2.0, 2.0], y = [5.0, 5.0, 0.0]

x + y = [7.0, 7.0, 2.0]

10x = [20.0, 20.0, 20.0]

|x| = 3.4641016151377544

= 20.0

|x-y| = 4.69041575982343

03、文档摘要类(Sketch)的设计和实现

文档摘要类(Sketch)用于封装文档的摘要信息。设计思路如下。

(1)定义带3个列表参数(text(文本)、k(k-grams)、d(文档摘要向量的维度))的构造函数。使用列表解析创建一个包含d个元素的列表freq(初始值为0),用于存储k-grams的频率。循环抽取文本的所有k-grams,并使用hash函数映射到0-d之间的整数,从而更新对应的列表freq的元素值(递增)。然后使用freq创建Vector对象vector,并调用向量对象的direction()方法进行归一化。最后把文档摘要向量vector并保存到实例对象属性_sketch。

(2)定义方法similarTo(),计算两个文档摘要向量的余弦相似度。

比较两个向量的常用方法包括欧几里得距离和余弦相似性度。给定向量x和y,其欧几里得距离定义为:

image.png


余弦相似性度定义为:

image.png


基于Vector对象,给定向量x和y,其欧几里得距离为abs(x – y),余弦相似性度的计算方法为x.dot(y)。

(3)重载方法str(),返回向量的字符串表示。

基于上述设计思想,向量(Sketch)的实现和测试代码如下所示。

【例2】文档摘要类(Sketch)的实现和测试(sketch.py)。

import sys
from vector import Vector
class Sketch:
    """计算文本text的k-grams的文档摘要向量(d维)"""
    def __init__(self, text, k, d):
        """初始化函数:计算文本text的文档摘要向量"""
        freq = [0 for i in range(d)] #创建长度为d的列表,初始值0
        for i in range(len(text) - k): #循环抽取k-grams,计算频率
            kgram = text[i:i+k]
            freq[hash(kgram) % d] += 1
        vector = Vector(freq) #创建文档摘要向量
        self._sketch = vector.direction() #归一化并赋值给对象实例变量
    def similarTo(self, other):
        """比较两个文档摘要对象Sketch的余弦相似度"""
        return self._sketch.dot(other._sketch)
    def __str__(self):
        return str(self._sketch)
#测试代码
def main():
    with open("tomsawyer.txt","r") as f:
        text = f.read()
        sketch = Sketch(text, 5, 100)
        print(sketch)
if __name__ == '__main__': main()

程序的运行结果如下。

[0.09151094195152963, …, 0.08903767325013694]
说明 /

哈希函数基于一个数值“种子”计算,在Python 3中,哈希种子会改变(缺省情况下),即给定对象的哈希值可能每次运行结果都不一样。因而,程序输出结果可能不同。

04、通过比较文档摘要确定文档的相似度

使用前文设计和实现的类Sketch,可以比较文档的相似度。

【例3】使用Sketch类比较文档的相似度(document_compare.py)。

import sys
from vector import Vector
from sketch import Sketch
#测试文档列表
filenames = [ 'gene.txt', 'pride.txt', 'tomsawyer.txt']
k = 5    #k-grams
d = 100000 #文档摘要向量维度
sketches = [0 for i in filenames]
for i in range(len(filenames)):
    with open(filenames[i], 'r') as f:
        text = f.read()
        sketches[i] = Sketch(text, k, d)
#输出结果标题
print(' '*15, end='')
for filename in filenames:
    print('{:>22}'.format(filename), end='')
print()
#输出结果比较明细
for i in range(len(filenames)):
    print('{:15}'.format(filenames[i]), end='')
    for j in range(len(filenames)):
        print('{:22}'.format(sketches[i].similarTo(sketches[j])), end='')
    print()

程序运行结果如下:

image.png


结果表明,相同文档的相似度为1,相同类型的文档(pride.txt和tomsawyer.txt)相似度比较大,而不同类型的文档(gene.txt和pride.txt)的相似度则比较低。
目录
相关文章
|
17天前
|
数据采集 缓存 定位技术
网络延迟对Python爬虫速度的影响分析
网络延迟对Python爬虫速度的影响分析
|
2月前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
19天前
|
数据采集 存储 JSON
Python爬虫开发中的分析与方案制定
Python爬虫开发中的分析与方案制定
|
26天前
|
数据可视化 开发者 Python
Python GUI开发:Tkinter与PyQt的实战应用与对比分析
【10月更文挑战第26天】本文介绍了Python中两种常用的GUI工具包——Tkinter和PyQt。Tkinter内置于Python标准库,适合初学者快速上手,提供基本的GUI组件和方法。PyQt基于Qt库,功能强大且灵活,适用于创建复杂的GUI应用程序。通过实战示例和对比分析,帮助开发者选择合适的工具包以满足项目需求。
83 7
|
2月前
|
数据可视化 算法 Python
基于OpenFOAM和Python的流场动态模态分解:从数据提取到POD-DMD分析
本文介绍了如何利用Python脚本结合动态模态分解(DMD)技术,分析从OpenFOAM模拟中提取的二维切片数据,以深入理解流体动力学现象。通过PyVista库处理VTK格式的模拟数据,进行POD和DMD分析,揭示流场中的主要能量结构及动态特征。此方法为研究复杂流动系统提供了有力工具。
79 2
基于OpenFOAM和Python的流场动态模态分解:从数据提取到POD-DMD分析
|
25天前
|
存储 数据处理 Python
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第27天】在科学计算和数据分析领域,Python凭借简洁的语法和强大的库支持广受欢迎。NumPy和SciPy作为Python科学计算的两大基石,提供了高效的数据处理和分析工具。NumPy的核心功能是N维数组对象(ndarray),支持高效的大型数据集操作;SciPy则在此基础上提供了线性代数、信号处理、优化和统计分析等多种科学计算工具。结合使用NumPy和SciPy,可以显著提升数据处理和分析的效率,使Python成为科学计算和数据分析的首选语言。
29 3
|
26天前
|
存储 机器学习/深度学习 算法
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第26天】NumPy和SciPy是Python科学计算领域的两大核心库。NumPy提供高效的多维数组对象和丰富的数学函数,而SciPy则在此基础上提供了更多高级的科学计算功能,如数值积分、优化和统计等。两者结合使Python在科学计算中具有极高的效率和广泛的应用。
43 2
|
2月前
|
数据采集 机器学习/深度学习 搜索推荐
Python自动化:关键词密度分析与搜索引擎优化
Python自动化:关键词密度分析与搜索引擎优化
|
2月前
|
数据可视化 算法 JavaScript
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
本文探讨了如何利用图论分析时间序列数据的平稳性和连通性。通过将时间序列数据转换为图结构,计算片段间的相似性,并构建连通图,可以揭示数据中的隐藏模式。文章介绍了平稳性的概念,提出了基于图的平稳性度量,并展示了图分区在可视化平稳性中的应用。此外,还模拟了不同平稳性和非平稳性程度的信号,分析了图度量的变化,为时间序列数据分析提供了新视角。
58 0
基于图论的时间序列数据平稳性与连通性分析:利用图形、数学和 Python 揭示时间序列数据中的隐藏模式
|
2月前
|
自然语言处理 算法 数据挖掘
探讨如何利用Python中的NLP工具,从被动收集到主动分析文本数据的过程
【10月更文挑战第11天】本文介绍了自然语言处理(NLP)在文本分析中的应用,从被动收集到主动分析的过程。通过Python代码示例,详细展示了文本预处理、特征提取、情感分析和主题建模等关键技术,帮助读者理解如何有效利用NLP工具进行文本数据分析。
50 2
下一篇
无影云桌面