Golang 文本相似度


原文链接: Golang 文本相似度

浅析文本相似度

浅析文本相似度 - 王琨的博客 - CSDN博客
dexyk/stringosim
Knowledge Graph 知识图谱入门 (六)
String similarity functions, String distance's, Jaccard, Levenshtein, Hamming, Jaro-Winkler, Q-grams, N-grams, LCS - Longest Common Subsequence, Cosine similarity...

package main

import (
	"fmt"

	"github.com/dexyk/stringosim"
)


func main() {
	// fmt.Println(stringosim.Jaccard([]rune("stringosim"), []rune("stingobim")))
	var src = []rune("公共资源交易中心")
	var t1 = []rune("公共资源交易中心1")
	var t2 = []rune("公共资源交易中心(市政府采购中心、市农村产权交易中心)")
	var t3 = []rune("对外贸易经济合作局机关服务站")
	fmt.Println(stringosim.Jaccard(src, src, []int{10})) //0
	fmt.Println(stringosim.Jaccard(src, t1, []int{10}))  //0.0625
	fmt.Println(stringosim.Jaccard(src, t2, []int{10}))  //0.7761194029850746
	fmt.Println(stringosim.Jaccard(src, t3, []int{10}))  //1
	println()
	fmt.Println(stringosim.Jaro(src, src)) //1
	fmt.Println(stringosim.Jaro(src, t1))  //0.9629629629629629
	fmt.Println(stringosim.Jaro(src, t2))  //0.7654320987654321
	fmt.Println(stringosim.Jaro(src, t3))  //0.3988095238095238
	println()
	fmt.Println(stringosim.JaroWinkler(src, src)) //1
	fmt.Println(stringosim.JaroWinkler(src, t1))  //0.9629629629629629
	fmt.Println(stringosim.JaroWinkler(src, t2))  //0.7654320987654321
	fmt.Println(stringosim.JaroWinkler(src, t3))  //0.3988095238095238
	println()
	fmt.Println(stringosim.QGram(src, src)) //0
	fmt.Println(stringosim.QGram(src, t1))  //1
	fmt.Println(stringosim.QGram(src, t2))  //57
	fmt.Println(stringosim.QGram(src, t3))  //58
	println()
	fmt.Println(stringosim.Cosine(src, src)) //0
	fmt.Println(stringosim.Cosine(src, t1))  //0.019419324309079777
	fmt.Println(stringosim.Cosine(src, t2))  //0.2849445141626511
	fmt.Println(stringosim.Cosine(src, t3))  //0.8780011437339162

}

TextSimilarity

这是一个类,里面包含的有关文本相似度的常用的计算算法,例如,最长公共子序列,最短标记距离,TF-IDF等算法
例如简单简单简单的用法:创建类实例,参数是两个文件目录,之后会生成两个字符串a.str_a, a.str_b

中文文本相似度计算的算法:

longest common subsequence
https://rosettacode.org/wiki/Longest_common_subsequence#Python

1、最长公共子串、编辑距离(基于原文本进行查找测试,)
可以进行改进

2、分词后进行集合操作。
Jaccard相似度、

3、是在分词后,得到词项的权重进行计算
结巴分词5--关键词抽取 http://www.cnblogs.com/zhbzz2007/p/6177832.html
余弦夹角算法、欧式距离、

simhash
一个python的包接口 http://leons.im/posts/a-python-implementation-of-simhash-algorithm/

1、分词,把需要判断文本分词形成这个文章的特征单词。最后形成去掉噪音词的单词序列并为每个词加上权重,我们假设权重分为5个级别(1~5)。比如:“ 美国“51区”雇员称内部有9架飞碟,曾看见灰色外星人 ” ==> 分词后为 “ 美国(4) 51区(5) 雇员(3) 称(1) 内部(2) 有(1) 9架(3) 飞碟(5) 曾(1) 看见(3) 灰色(4) 外星人(5)”,括号里是代表单词在整个句子里重要程度,数字越大越重要。

2、hash,通过hash算法把每个词变成hash值,比如“美国”通过hash算法计算为 100101,“51区”通过hash算法计算为 101011。这样我们的字符串就变成了一串串数字,还记得文章开头说过的吗,要把文章变为数字计算才能提高相似度计算性能,现在是降维过程进行时。hash算法的设置,就是python里面的字典。



3、加权,通过 2步骤的hash生成结果,需要按照单词的权重形成加权数字串,比如“美国”的hash值为“100101”,通过加权计算为“4 -4 -4 4 -4 4”;“51区”的hash值为“101011”,通过加权计算为 “ 5 -5 5 -5 5 5”。

4、合并,把上面各个单词算出来的序列值累加,变成只有一个序列串。比如 “美国”的 “4 -4 -4 4 -4 4”,“51区”的 “ 5 -5 5 -5 5 5”, 把每一位进行累加, “4+5 -4+-5 -4+5 4+-5 -4+5 4+5” ==》 “9 -9 1 -1 1 9”。这里作为示例只算了两个单词的,真实计算需要把所有单词的序列串累加。

5、降维,把4步算出来的 “9 -9 1 -1 1 9” 变成 0 1 串,形成我们最终的simhash签名。 如果每一位大于0 记为 1,小于0 记为 0。最后算出结果为:“1 0 1 0 1 1”。

总结 simhash用于比较大文本,比如500字以上效果都还蛮好,距离小于3的基本都是相似,误判率也比较低
每篇文档得到SimHash签名值后,接着计算两个签名的海明距离即可。根据经验值,对64位的 SimHash值,海明距离在3以内的可认为相似度比较高。

海明距离的求法:异或时,只有在两个比较的位不同时其结果是1 ,否则结果为0,两个二进制“异或”后得到1的个数即为海明距离的大小。

Jaccard相似性系数
引用资料:http://www.ruanyifeng.com/blog/2013/03/cosine_similarity.html
(1)使用TF-IDF算法,找出两篇文章的关键词;
(2)每篇文章各取出若干个关键词(比如20个),合并成一个集合,计算每篇文章对于这个集合中的词的词频(为了避免文章长度的差异,可以使用相对词频);
(3)生成两篇文章各自的词频向量;
(4)计算两个向量的余弦相似度,值越大就表示越相似。
(5) 或者计算两个向量的欧几里德距离,值越小越相近

导入文档
1、分词(python jieba分词)
已安装、需要简单学习使用

2、用tf-idf计算词语权重 python scikit-learn计算tf-idf词语权重
简单理解tf-idf的原理,使用库函数
样例使用地址: http://www.tuicool.com/articles/U3uiiu

3、使用各个算法计算文档的相似度

a = TextSimilarity('/home/a.txt','/home/b.txt')
a.minimumEditDistance(a.str_a,a.str_b)
# Out[89]: 0.3273657289002558

a.JaccardSim(a.str_a,a.str_b)
# Out[90]: 0.17937219730941703

a.splitWordSimlaryty(a.str_a,a.str_b,sim=a.pers_sim)
# Out[91]: 0.54331148827606712
`