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
更多使用细节,参考开源地址:
写在完结前
涉及的项目
汉字的相似度计算到这里算是告一段落。
主要涉及的资料及项目有:
当然,还可以结果 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 {
@Override
public 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 开源形近字算法补完计划(完结篇)的更多相关文章
- [TaskList] 省选前板子补完计划
省选前本子补完计划 [ ] 带权并查集 [ ] 树上莫队 - UOJ58 [WC2013]糖果公园 loj2485「CEOI2017」Chase
- QBXT 2017GoKing problems 补完计划
10.11 Updata : 烦死了...麻烦死了...不补了..就这些吧 20171001 上: 100 + 90 + 90 = 280 = rank 8 T1 /* T1 从最大的数开始倒着枚举 ...
- bzoj Usaco补完计划(优先级 Gold>Silver>资格赛)
听说KPM初二暑假就补完了啊%%% 先刷Gold再刷Silver(因为目测没那么多时间刷Silver,方便以后TJ2333(雾 按AC数降序刷 ---------------------------- ...
- NodeJS学习:爬虫小探补完计划
说明:本文在个人博客地址为edwardesire.com,欢迎前来品尝. 书接上回,我们需要修改程序以达到连续抓取40个页面的内容.也就是说我们需要输出每篇文章的标题.链接.第一条评论.评论用户和论坛 ...
- CodeVS1169 传纸条 [DP补完计划]
题目传送门 题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端, ...
- 洛谷P2224 [HNOI2001] 产品加工 [DP补完计划,背包]
题目传送门 产品加工 题目描述 某加工厂有A.B两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成.由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时 ...
- POJ1742 Coin [DP补完计划]
题目传送门 Coins Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 41707 Accepted: 14125 Des ...
- 洛谷P1280 尼克的任务 [DP补完计划]
题目传送门 题目描述 尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成. 尼克的一个工作日为N分钟,从 ...
- PHP函数补完:stream_context_create()模拟POST/GET
PHP函数补完:stream_context_create()模拟POST/GET PHP流的创建 在 2011年01月08日 那天写的 已经有 9408 次阅读了 感谢 参考或原文 服务 ...
随机推荐
- Vue3学习(五)之集成HTTP库axios
一.安装axios npm install axios@0.21.0 --save 二.axios的使用 1.在主页中引用axios 在Vue3新增了setup初始化方法,所以我们在这里开始使用并测试 ...
- [Git系列] 前言
Git 简介 Git 是一个重视速度的分布式版本控制和代码管理系统,最初是由 Linus Torvalds 为开发 Linux 内核而设计并开发的,是一款遵循二代 GUN 协议的免费软件.这一教程会向 ...
- vue3.x新特性之setup函数,看完就会用了
最近有小伙伴跟我聊起setup函数,因为习惯了vue2.x的写法导致了,setup用起来觉得奇奇怪怪的,在一些api混编的情况下,代码变得更加混乱了,个人觉得在工程化思想比较强的团队中使用setup确 ...
- Java:并发笔记-09
Java:并发笔记-09 说明:这是看了 bilibili 上 黑马程序员 的课程 java并发编程 后做的笔记 7. 共享模型之工具-2 原理:AQS 原理 对于 AQS 的原理这部分内容,没很好的 ...
- Golang通脉之反射
什么是反射 官方关于反射定义: Reflection in computing is the ability of a program to examine its own structure, pa ...
- BUAA 2020 软件工程 结对项目作业
Author: 17373051 郭骏 3.28添加:4.计算模块接口的设计与实现过程部分,PairCore实现的细节 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) ...
- spring session实现session统一管理(jdbc实现)
最近在看一些关于spring session 的知识,特做一个笔记记录一下. 在项目中经常会遇到这么一种情况,同一个web项目有时需要部署多份,然后使用nginx实现负载均衡,那么遇到的问题就是,部署 ...
- 如何清理history
工作中,需要清理history 清理当前会话历史命令 history -c 清理当前用户所有历史命令 echo > .bash_history #在用户主目录执行此操作
- 从零开始的DIY智能家居 - 基于 ESP32 的土壤湿度传感器
前言 自从上次做了那个 甲醛传感器 和 水浊度传感器 之后开始尝到智能家居的甜头了,这两东西有没有用我不知道,但是没事的时候掏出手机瞄两眼,看着就让人很安心( ̄︶ ̄). 于是懒惰的我开始琢磨把给植物浇 ...
- PCIE学习链接集合
<PCIE基础知识+vivado IP core设置> https://blog.csdn.net/eagle217/article/details/81736822 <一步一步开始 ...