python读取doc文件 语义识别_自然语言处理(NLP)语义分析--文本相似度

文本相似度及案例

​ 在做自然语言处理的过程中,我们经常会遇到需要找出相似语句的场景,或者找出句子的近似表达,这时候就需要把类似的句子归到一起,这里面就涉及到句子相似度计算的问题。

基本方法

句子相似度计算一共归类了以下几种方法:

编辑距离计算

杰卡德系数计算

TF 计算

TF-IDF 计算

Word2Vec 计算

下面来一一了解一下这几种算法的原理和 Python 实现。

编辑距离计算

编辑距离,英文叫做 Edit Distance,又称 Levenshtein 距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,如果它们的距离越大,说明它们越是不同。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

例如我们有两个字符串:string 和 setting,如果我们想要把 string 转化为 setting,需要这么两步:

第一步,在 s 和 t 之间加入字符 e。

第二步,把 r 替换成 t。

所以它们的编辑距离差就是 2,这就对应着二者要进行转化所要改变(添加、替换、删除)的最小步数。

那么用 Python 怎样来实现呢,我们可以直接使用 distance 库:

#编辑距离

import distance

def edit_distance(s1, s2):

return distance.levenshtein(s1, s2)

strings = [

'你在干什么',

'你在干啥子',

'你在做什么',

'你好啊',

'我喜欢吃香蕉'

]

target = '你在干啥'

results = list(filter(lambda x: edit_distance(x, target) <= 2, strings))

print(results)

'''

['你在干什么', '你在干啥子']

'''1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

​ 通过这种方式我们可以大致筛选出类似的句子,但是发现一些句子例如“你在做什么” 就没有被识别出来,但他们的意义确实是相差不大的,因此,编辑距离并不是一个好的方式,但是简单易用。

杰卡德系数计算

杰卡德系数,英文叫做 Jaccard index, 又称为 Jaccard 相似系数,用于比较有限样本集之间的相似性与差异性。Jaccard 系数值越大,样本相似度越高。

实际上它的计算方式非常简单,就是两个样本的交集除以并集得到的数值,当两个样本完全一致时,结果为 1,当两个样本完全不同时,结果为 0。

算法非常简单,就是交集除以并集,下面我们用 Python 代码来实现一下:

#杰卡德系数计算

from sklearn.feature_extraction.text import CountVectorizer

import numpy as np

def jaccard_similarity(s1, s2):

def add_space(s):

return ' '.join(list(s))

# 将字中间加入空格

s1, s2 = add_space(s1), add_space(s2)

# 转化为TF矩阵

cv = CountVectorizer(tokenizer=lambda s: s.split())

corpus = [s1, s2]

vectors = cv.fit_transform(corpus).toarray()

# 求交集

numerator = np.sum(np.min(vectors, axis=0))

# 求并集

denominator = np.sum(np.max(vectors, axis=0))

# 计算杰卡德系数

return 1.0 * numerator / denominator

s1 = '你在干嘛呢'

s2 = '你在干什么呢'

print(jaccard_similarity(s1, s2))

'''

0.5714285714285714

'''1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

这个数值越大,代表两个字符串越接近,否则反之,因此我们也可以使用这个方法,并通过设置一个相似度阈值来进行筛选。

TF 计算

第三种方案就是直接计算 TF 矩阵中两个向量的相似度了,实际上就是求解两个向量夹角的余弦值,就是点乘积除以二者的模长,公式如下:

cosθ=a·b/|a|*|b|

上面我们已经获得了 TF 矩阵,下面我们只需要求解两个向量夹角的余弦值就好了,代码如下:

from sklearn.feature_extraction.text import CountVectorizer

import numpy as np

from scipy.linalg import norm

def tf_similarity(s1, s2):

def add_space(s):

return ' '.join(list(s))

# 将字中间加入空格

s1, s2 = add_space(s1), add_space(s2)

# 转化为TF矩阵

cv = CountVectorizer(tokenizer=lambda s: s.split())

corpus = [s1, s2]

vectors = cv.fit_transform(corpus).toarray()

# 计算TF系数

return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

s1 = '你在干嘛呢'

s2 = '你在干什么呢'

print(tf_similarity(s1, s2))

'''

#使用np.dot() 方法获取向量的点乘积,然后通过 norm() 方法获取向量的模长,经计算得到二者的 TF 系数

0.7302967433402214

'''1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

TFIDF 计算

还可以计算 TF-IDF 系数,TF-IDF 实际上就是在词频 TF 的基础上再加入 IDF 的信息,IDF 称为逆文档频率。

借助于 Sklearn 中的模块 TfidfVectorizer 来实现,代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer

import numpy as np

from scipy.linalg import norm

def tfidf_similarity(s1, s2):

def add_space(s):

return ' '.join(list(s))

# 将字中间加入空格

s1, s2 = add_space(s1), add_space(s2)

# 转化为TF矩阵

cv = TfidfVectorizer(tokenizer=lambda s: s.split())

corpus = [s1, s2]

vectors = cv.fit_transform(corpus).toarray()

# 计算TF系数

return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

s1 = '你在干嘛呢'

s2 = '你在干什么呢'

print(tfidf_similarity(s1, s2))

'''

0.5803329846765686

'''1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

Word2Vec 计算

Word2Vec,顾名思义,其实就是将每一个词转换为向量的过程。可参考word2vec和doc2vec的介绍。

你可能感兴趣的:(python读取doc文件,语义识别)