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

news2025/2/2 9:47:43

图片

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

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,其欧几里得距离定义为:

图片

 余弦相似性度定义为:

图片

 

基于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()

 程序运行结果如下:

图片

结果表明,相同文档的相似度为1,相同类型的文档(pride.txt和tomsawyer.txt)相似度比较大,而不同类型的文档(gene.txt和pride.txt)的相似度则比较低。 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/762565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot第30集:springboot集合问题

Logstash Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据、格式化数据,然后将数据发送到es进行存储。 ElasticSearch Elasticsearch 是基于JSON的分布式搜索和分析引擎,是利用倒排索引实现的全文索引。 KibanaKibana 能够…

低代码项目实战第一弹!2人14天快速构建电商企业供应链管理平台(一)

一、前言:项目背景 项目情况:一家主要通过电商平台销售日用清洁用品的企业,淘宝垂直品类第一,销售模式包括自营和代理商两种模式,平时用旺店通ERP进行订单管理和财务结算。并且客户公司有小的开发团队,可以…

Java日期类

日期类 第一代日期类: 1、Date:精确到毫秒,代表特定的瞬间 2、SimpleDateFormat: **格式化和解析日期的具体类,**它允许进行:格式化(日期 → 文本) 解析(文本 → 日期) 和 规范化。 3、常用的使用方法…

sentinel介绍-分布式微服务流量控制

官网地址 https://sentinelguard.io/ 介绍 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自…

MySQL 知识连载(一)

点击上方↑“追梦 Java”关注,一起追梦! MySQL 是一款开源软件,凭借其出色的性能,目前已经成为绝大多数互联网公司的首选关系型数据库。因此程序员不能只懂数据库的增删改查和一些简单的使用技巧,更需要熟练掌握 MySQL…

MySQL八股学习历程3MySQL数据页的格式from小林coding

MySQL八股学习历程3MySQL数据页的格式from小林coding InnoDB数据页MySQL单表建议数据承载量探究 InnoDB数据页 InnoDB 的数据是按数据页为单位来读写的,每个数据页大小默认为16KB,数据页的格式如下图 文件头中有两个指针,指向上一个数据页和下一个数据页,使得页面连接成一个…

大佬带你体验华为云代码检查服务CodeArts Check

1 开发者的自述 作为开发者,刚开始都不希望有任何针对他代码的批评,因为一旦知道代码被检测出问题,就会付出额外的努力做好工作,实际上,从一个开发人员的编码中,你能更清楚地了解编程语言可以做什么&#…

单片机裸机程序框架是怎样的?

单片机裸机程序框架指的是在单片机上进行编程时,不依赖任何操作系统或高级库的纯裸机编程框架。这意味着你需要直接操作底层硬件和寄存器,以完成特定的任务。下面是一个典型的单片机裸机程序框架,以C语言为例: // 头文件包含&…

分布式kmeans(scala原码实现)

scala分布式kmeans 1.分布式Kmeans算法设计思路2.分布式Kmeans算法代码实现2.1 Driver(主要负责分配、汇总数据)2.2 Executor(主要负责计算)2.3 Executor2(主要负责计算) 3.分布式Kmeans算法spark集群部署3…

如何解决笔记本电脑键盘失灵的问题:3个简单而有效的解决方法

当你使用笔记本电脑时,可能会遇到键盘失灵的情况,这是一件非常令人恼火的事情。然而,不要担心,下面将为你提供三个简单而有效的解决方法。 首先,检查连接和驱动程序。请确保键盘与笔记本电脑的连接正常,有时…

数据结构与算法之美总结(数组、链表、栈、队列、递归、排序及二分)

title: 数据结构与算法之美总结(数组、链表、栈、队列、递归、排序及二分) date: 2023-04-15 01:41:26 tags: 数据结构算法 categories:数据结构与算法 cover: https://cover.png feature: false 1. 前言 1、什么是数据结构?什么是算法&…

SpringCloud Alibaba组件之Seata安装部署

seata server(TC) 部署 部署指南:https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html 下载地址:https://github.com/seata/seata/tags 版本对应关系:SpringCloud Alibaba 组件对应关系说明 下载 通过查…

Minio部署总结

官方介绍 MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小&#xf…

一文搞懂数据库索引原理

前言 写数据库,我第一时间就想到了MySQL、Oracle、索引、存储过程、查询优化等等。 不知道大家是不是跟我想得一样,我最想写的是索引,为啥呢? 以下这个面试场景,不知道大家熟悉不熟悉: 面试官:数…

郑州网站域名升级https通配符证书

新创建的网站如果没有安装SSL证书,在客户端与服务器传输信息时会使用明文传输,明文传输的数据容易被其他人截获或者插入违法信息,会对网站所有者和访问网站的客户带来危害。而部署了SSL证书将网站域名由http升级为https,会在客户端…

【PHP面试题51】Swoole是什么?有什么特点,主要解决了什么问题

文章目录 一、前言二、什么是Swoole?三、如何使用Swoole?四、Swoole主要解决了什么问题?4.1 高性能4.2 高并发4.3 异步编程4.4 多协议支持 五、总结 一、前言 本文已收录于PHP全栈系列专栏:PHP面试专区。 计划将全覆盖PHP开发领域…

jdk1.8安装教程及环境变量配置(含jdk8,11,13安装文件)

目录 友情提醒第一章、JVM、JRE、JDK介绍第二章、下载和安装JDK2.1)百度网盘直接下载免安装2.2)官网下载安装JDK(需要收费) 第三章、环境变量配置3.1)windows环境变量配置3.2)验证环境变量是否配置成功 友情…

spark启动HA时workers为0,且为standby状态

今天学习一个spark视频,在启动StandAloneHa模式的时候,发现workers为0,而且spark两个master的状态都为standby,找了很久,才知道我用的spark3.2 最低支撑的zookeeper版本为3.5.x,而且zookeeper的安装包是需要带bin的那个…

自学C++(4)

1、友元 友元的目的就是让一个函数或者类访问另一个类中private成员 1.1全局函数做友元 写法:在类外定义一个全局函数,如果这个函数访问到了类中private成员,则需要在这个类中声明这个函数为private类型。 这里需要注意的是全局函数形参的…

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树、Pipeline、交叉验证

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树案例 除了scikit-learn外,在spark中也提供了机器学习库,即Spark MLlib。 在Spark MLlib机器学习库提供两套算法实现的API:基于RDD API和基于DataFrame API。今天,主要介绍下Data…