NLP 开源形近字算法补完计划(完结篇)

2023-10-22 04:58

本文主要是介绍NLP 开源形近字算法补完计划(完结篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

所有的故事都有开始,也终将结束。

本文将作为 NLP 汉字相似度的完结篇,为该系列画上一个句号。

起-NLP 中文形近字相似度计算思路

承-中文形近字相似度算法实现,为汉字 NLP 尽一点绵薄之力

转-当代中国最贵的汉字是什么?

不足之处

之所以有本篇,是因为上一次的算法实现存在一些不足。

巴别塔

《圣经》中有关于巴别塔建造,最终人们因为语言问题而停工的故事​。

巴别塔

创11:6 “看哪!他们成为一样的人民,都是一样的言语,如今既作起这事来,以后他们所要作的事,就没有不成就的了。创11:7 我们下去,在那里变乱他们的口音,使他们的言语彼此不通。”创11:8 于是,耶和华使他们从那里分散在全地上;他们就停工不造那城了。

为了避免语言问题,我一开始就实现了一个 exe4j 打包的对比程序,自己跑的很顺畅。

小伙伴一跑,运行失败。各种环境配置一顿操作,最后还是报错。

于是,我写了一个 python 简易版本,便于做 NLP 研究的小伙伴们学习。

https://github.com/houbb/nlp-hanzi-similar/releases/tag/pythn

java 是一种语言,python 是一种语言。

编程语言,让人和机器之间可以沟通,却让人与人之间产生了隔阂。

拆字

在 当代中国最贵的汉字是什么? 一文中,我们首次说明了汉字的拆合。

汉字的拆分实现,核心目的之一就是为了完善汉字的相似度比较。

通过对比汉字的拆分部分,然后获取拆字的相似度,提高对比的准确性。

拆字相似度

简单的需求

为了便于小伙伴们理解,我们用产品经理的思维和大家介绍一下实现方式。

我的需求比较简单。你看,【明】可以拆分【日】【月】,【冐】也可以拆分为【日】【月】。对比一下,结果是显然的。怎么实现我不管,明天上线吧。

小伙伴们,应该已经知道怎么实现了吧?

简单

使用体验

诚如产品所言,这个需求已经实现。

maven 引入

<dependency><groupId>com.github.houbb</groupId><artifactId>nlp-hanzi-similar</artifactId><version>1.2.0</version>
</dependency>

使用

double rate1 = HanziSimilarHelper.similar('末', '未');

对应的结果为:0.9696969696969697

更多使用细节,参考开源地址:

https://github.com/houbb/nlp-hanzi-similar

写在完结前

涉及的项目

汉字的相似度计算到这里算是告一段落。

主要涉及的资料及项目有:

拼音

拆字

四角编码词库

汉字结构词库

汉字偏旁词库

笔画数词库

当然,还可以结果 opencc4j 进行繁简体的处理,此处不再延伸。

之后的计划

NLP 的领域还有很多东西需要大家攻克,毕竟中文 NLP 才刚刚开始。

技术尚未成功,同志仍需努力。

据说最近鹅城的某位黄老爷惹得大家怨声载道。

很多小伙伴说,如果有一款软件可以实现【月丷夫马言卂彳山兀攴人言】的沟通功能,那么我肯定会用。

所谓说者无心,听者有意。

写一个通讯软件,主要是为了巩固下 netty 的学习,其他的都不重要。

没有你,对我很重要

虽然知道就算有,大家肯定也不太会改变,但是老马还是准备试试。

java 实现思路

警告,如果你头发已经所剩无几,或者对实现并不感兴趣。

那么就可以收藏+点赞+评论【不明觉厉】,然后离开了。

下面是枯燥的代码实现环节。

轻松

程序员的思维

下面是程序员的思维。

首先要解决几个问题:

(1)汉字的拆分实现

这个直接复用已经实现的汉字拆分实现。

List<String> stringList = ChaiziHelper.chai(charWord.charAt(0));

相同的一个汉字可以有多种拆分方式,简单起见,我们默认取第一个。

(2)相似的比较

假设我们对比 A B 两个汉字,可以拆分为如下的子集。

A = {A1, A2, …, Am}

B = {B1, B2, …, Bm}

/*** 获取拆分后对应的拆分字符* @param charWord 字符* @return 结果*/
private char[] getSplitChars(String charWord) {List<String> stringList = ChaiziHelper.chai(charWord.charAt(0));// 这里应该选择哪一个是有讲究的。此处为了简单,默认选择第一个。String string = stringList.get(0);return string.toCharArray();
}

拆分后的子集对比有多种实现方式,简单起见,我们直接遍历元素,判断另一个子集是否存在。

当然,遍历的时候要以拆分数量较少的的为基准。

int minLen = Math.min(charsOne.length, charsTwo.length);// 比较
double totalScore = 0.0;
for(int i = 0; i <  minLen; i++) {char iChar = charsOne[i];String textChar = iChar+"";if(ArrayPrimitiveUtil.contains(charsTwo, iChar)) {//累加分数}
}

(3)拆分子集的权重

比如 两个汉字都是子集,但是因为笔画数不同,权重也不同。

我们用一个子集的笔画数占整体汉字的笔画数计算权重。

 int textNumber = getNumber(textChar, similarContext);double scoreOne = textNumber*1.0 / numberOne * 1.0;
double scoreTwo = textNumber*1.0 / numberTwo * 1.0;totalScore += (scoreOne + scoreTwo) / 2.0;

ps: 这里的除以 2,是为了归一化。保证最后的结果在 0-1 之间。

(4)笔画数

获取笔画数的方式,我们可以直接复用以前的方法。

如果没有匹配的,默认笔画数为 1。

private int getNumber(String text, IHanziSimilarContext similarContext) {Map<String, Integer> map = similarContext.bihuashuData().dataMap();Integer number = map.get(text);if(number == null) {return 1;}return number;
}

java 完整实现

我们把所有的碎片拼接起来,就得到一个完整的实现。

/*** 拆字** @author 老马啸西风* @since 1.0.0*/
public class ChaiziSimilar implements IHanziSimilar {@Overridepublic double similar(IHanziSimilarContext similarContext) {String hanziOne = similarContext.charOne();String hanziTwo = similarContext.charTwo();int numberOne = getNumber(hanziOne, similarContext);int numberTwo = getNumber(hanziTwo, similarContext);// 拆分char[] charsOne = getSplitChars(hanziOne);char[] charsTwo = getSplitChars(hanziTwo);int minLen = Math.min(charsOne.length, charsTwo.length);// 比较double totalScore = 0.0;for(int i = 0; i <  minLen; i++) {char iChar = charsOne[i];String textChar = iChar+"";if(ArrayPrimitiveUtil.contains(charsTwo, iChar)) {int textNumber = getNumber(textChar, similarContext);double scoreOne = textNumber*1.0 / numberOne * 1.0;double scoreTwo = textNumber*1.0 / numberTwo * 1.0;totalScore += (scoreOne + scoreTwo) / 2.0;}}return totalScore * similarContext.chaiziRate();}/*** 获取拆分后对应的拆分字符* @param charWord 字符* @return 结果*/private char[] getSplitChars(String charWord) {List<String> stringList = ChaiziHelper.chai(charWord.charAt(0));// 这里应该选择哪一个是有讲究的。此处为了简单,默认选择第一个。String string = stringList.get(0);return string.toCharArray();}/*** 获取笔画数* @param text 文本* @param similarContext 上下文* @return 结果*/private int getNumber(String text, IHanziSimilarContext similarContext) {Map<String, Integer> map = similarContext.bihuashuData().dataMap();Integer number = map.get(text);if(number == null) {return 1;}return number;}}

小结

本文引入了汉字拆字,进一步丰富了相似度的实现。

当然,实现本身依然有很多值得提升的地方,比如拆分后的选择,是否可以递归拆分等,这个还是留给后人研究吧。

我是老马,期待与你的下次重逢。

在这里插入图片描述

这篇关于NLP 开源形近字算法补完计划(完结篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/259166

相关文章

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

无需邀请码!Manus复刻开源版OpenManus下载安装与体验

《无需邀请码!Manus复刻开源版OpenManus下载安装与体验》Manus的完美复刻开源版OpenManus安装与体验,无需邀请码,手把手教你如何在本地安装与配置Manus的开源版OpenManu... Manus是什么?Manus 是 Monica 团队推出的全球首款通用型 AI Agent。Man

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1