• R语言实践 »
  • 用R语言实现点积相似度Dot Product Similarity

用R语言实现点积相似度Dot Product Similarity

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-dot-product-similarity/

前言

在文字处理时,我们经常需要判断两段文字是否相似,计算文本相似度有很多度种方法,文本将介绍最简单,也是计算最高效的一种方法点积相似度,与余弦相似度很像,与欧式距离相似度也很像。

目录

  1. 点积相似度介绍
  2. R语言实现点积计算
  3. 点积相似度应用

1. 点积相似度介绍

点积在数学中,又称数量积(dot product 或者 scalar product),是指接受在实数R上的两个向量并计算它们对应元素的乘机之和,也是欧几里得空间的标准内积。当两个向量进行点积操作时,结果的大小可以反映两个向量的相似性。这是因为点积操作考虑了向量的方向和大小。

点积计算

点积有两种定义方式:代数方式和几何方式。通过在欧氏空间中引入笛卡尔坐标系,向量之间的点积既可以由向量坐标的代数运算得出,也可以通过引入两个向量的长度和角度等几何概念来求解。

代数方式:

两个向量a = [a1, a2,…, an]和b = [b1, b2,…, bn]的点积定义为:

几何方式:

点积相似度

点积相似度,是一种计算两个向量之间相似性的方法,对于两个向量a和b,它们的点积相似度为它们对应元素的乘机之和。

假设我们有两个向量 A 和 B,它们的点积定义为:

A . B = |A| * |B| * cos(θ)
其中,|A| 和 |B| 分别是 A 和 B 的长度,θ 是 A 和 B 之间的夹角。
  • 当 A 和 B 的方向相同时(即它们的夹角接近0),cos(θ) 接近 1,所以 A . B 较大。这表明 A 和 B 很相似。
  • 当 A 和 B 的方向相反时(即它们的夹角接近180度),cos(θ) 接近 -1,所以 A . B 较小,甚至为负。这表明 A 和 B 不相似。
  • 当 A 和 B 互相垂直时(即它们的夹角为90度),cos(θ) 为 0,所以 A . B 为 0。这表明 A 和 B 没有相似性。

因此,通过计算向量的点积,我们可以得到一个衡量两个向量相似性的标量值。在深度学习中,尤其是在自然语言处理和推荐系统中,我们经常需要衡量和比较向量(例如,单词嵌入或用户和物品的嵌入)的相似性。在这些情况下,点积是一种简单且有效的方法。

2. R语言实现点积计算

根据公式计算点积是很简单的,用R语言的基本函数,就可以完成点积的计算。

首先,定义2个向量a和b。


> a <- c(2, 5, 6)
> b <- c(4, 3, 2)

代数方式实现


> fun1<-function(a,b){
+   sum(a*b)
+ }
> 
> fun1(a,b)
[1] 35

几何方式实现


> fun2<-function(a,b){
+   a %*% b  
+ }
> 
> fun2(a,b)
     [,1]
[1,]   35

3. 点积相似度应用

接下来,我们设置一个场景,用点积相似度计算,计算不同人的简历的相似度。

假设有三个求职者A,B,C,从简历中提取了5个属性,分别是:性别、学历、籍贯、编程语言、职位。

姓名性别学历籍贯编程语言职位
A本科浙江JAVA开发工程师
B硕士北京R算法工程师
C本科上海JAVA开发工程师

那么,我们可以把上面的表格转换为一个矩阵:


[
[男	本科	浙江	JAVA	开发工程师],
[女	硕士	北京	R	算法工程师],
[男	本科	上海	JAVA	开发工程师],
]

然后,我们把这个矩阵转置:


[
[男, 女, 男]
[本科, 硕士, 本科],
[浙江, 北京, 上海],
[JAVA, R, JAVA],
[开发工程师, 算法工程师, 开发工程师]
]

计算上面2个矩阵的点积,计算过程为:


[
[男 * 男 + 本科 * 本科 + 浙江 * 浙江 + JAVA * JAVA + 开发工程师*开发工程师,
男 * 女 + 本科 * 硕士 + 浙江 * 北京 + JAVA * R + 开发工程师*算法工程师,
男 * 男 + 本科 * 本科 + 浙江 * 上海 + JAVA * JAVA + 开发工程师*开发工程师],
[女 * 男 + 硕士 * 本科 + 北京 * 浙江 + R * JAVA + 算法工程师*开发工程师,
女 * 女 + 硕士 * 硕士 + 硕士 * 硕士 + R * R + 算法工程师*算法工程师,
女 * 男 + 硕士 * 本科 + 北京 * 上海 + R * JAVA + 算法工程师*开发工程师],
[男 * 男 + 本科 * 本科 + 上海 * 浙江 + JAVA * JAVA + 开发工程师*开发工程师,
男 * 女 + 本科 * 硕士 + 上海 * 北京 + JAVA * R + 开发工程师*算法工程师,
男 * 男 + 本科 * 本科 + 上海 * 上海 + JAVA * JAVA + 开发工程师*开发工程师],
]

这里为了便于计算,我们假设将值相等的点积值设为1,不相等设为0,计算结果为一个3*3的矩阵,得到计算结果为:


[
[5, 0, 4]
[0, 5, 0]
[4, 0, 5]
]

我们可以认为这个矩阵代表了,三个人之间两两的关联度,数值越大越相似。

ABC
A504
B050
C405

于是,这样我们再比较简历的时候,就可以判断谁和谁比较相似了。词向量计算,和这个计算过程是类似的。因此,在文本的的匹配过程中,每个词都可以找到与之相似度分数最高的一个关联词。

最后,我们用R语言来模拟上面的手动计算过程。

首先,用R语言来构建数据集resume。


> resume<-data.frame(
+   `姓名`=c('A','B','C'),
+   `性别`=c('男','女','男'),
+   `学历`=c('本科','硕士','本科'),
+   `籍贯`=c('浙江','北京','上海'),
+   `编程语言`=c('JAVA','R','JAVA'),
+   `职位`=c('开发工程师','算法工程师','开发工程师')
+ )

> resume
  姓名 性别 学历 籍贯 编程语言       职位
1    A   男 本科 浙江     JAVA 开发工程师
2    B   女 硕士 北京        R 算法工程师
3    C   男 本科 上海     JAVA 开发工程师

把data.frame矩阵化,同时建立转置矩阵


> m1<-resume[,-1];m1
  性别 学历 籍贯 编程语言       职位
1   男 本科 浙江     JAVA 开发工程师
2   女 硕士 北京        R 算法工程师
3   男 本科 上海     JAVA 开发工程师
> m2<-t(m1);m2
         [,1]         [,2]         [,3]        
性别     "男"         "女"         "男"        
学历     "本科"       "硕士"       "本科"      
籍贯     "浙江"       "北京"       "上海"      
编程语言 "JAVA"       "R"          "JAVA"      
职位     "开发工程师" "算法工程师" "开发工程师"

建立函数dot_similary(),完成点积的计算,得到点积相似度矩阵。本文的代码实现过程,没有使用矩阵的方法来实现,因此这里主要是介绍计算思路。


> dot_similary<-function(df){
+   m1<-df[,-1];m1
+   m2<-t(m1);m2
+   
+   n<-nrow(m1)
+   mm<-matrix(0,nrow=n,ncol=n)
+   for(i in 1:n){
+     for(j in 1:n){
+       v<-length(which(m1[i,]==m2[,j]))    
+       mm[i,j]<-v
+     }
+   }
+   
+   colnames(mm)<-df[,1]
+   rownames(mm)<-df[,1] + mm + } # 运行函数,获得结果 

> dot_similary(resume)
  A B C
A 5 0 4
B 0 5 0
C 4 0 5

如果看看计算过程,可以打印矩阵点积计算的过程。


> row1<-paste(
+   paste(paste(m1[1,],m2[,1], sep='*'),collapse = "+"),
+   paste(paste(m1[1,],m2[,2], sep='*'),collapse = "+"),
+   paste(paste(m1[1,],m2[,3], sep='*'),collapse = "+"),
+   sep=","
+ )
> row1
[1] "男*男+本科*本科+浙江*浙江+JAVA*JAVA+开发工程师*开发工程师,男*女+本科*硕士+浙江*北京+JAVA*R+开发工程师*算法工程师,男*男+本科*本科+浙江*上海+JAVA*JAVA+开发工程师*开发工程师"
 
> row2<-paste(
+   paste(paste(m1[2,],m2[,1], sep='*'),collapse = "+"),
+   paste(paste(m1[2,],m2[,2], sep='*'),collapse = "+"),
+   paste(paste(m1[2,],m2[,3], sep='*'),collapse = "+"),
+   sep=","
+ )
> row2
[1] "女*男+硕士*本科+北京*浙江+R*JAVA+算法工程师*开发工程师,女*女+硕士*硕士+北京*北京+R*R+算法工程师*算法工程师,女*男+硕士*本科+北京*上海+R*JAVA+算法工程师*开发工程师"
 
> row3<-paste(
+   paste(paste(m1[3,],m2[,1], sep='*'),collapse = "+"),
+   paste(paste(m1[3,],m2[,2], sep='*'),collapse = "+"),
+   paste(paste(m1[3,],m2[,3], sep='*'),collapse = "+"),
+   sep=","
+ )
> row3
[1] "男*男+本科*本科+上海*浙江+JAVA*JAVA+开发工程师*开发工程师,男*女+本科*硕士+上海*北京+JAVA*R+开发工程师*算法工程师,男*男+本科*本科+上海*上海+JAVA*JAVA+开发工程师*开发工程师"

本文我们了解点积相似度的原理和实现,并且应用了点积似度,对简历中的人进行了相似度的计算,从而可以判断两个人之间的相似程度,让我们进行文本匹配时又多了一种方法。本文代码:https://github.com/bsspirit/r-string-match/blob/main/dotproduct.r

转载请注明出处:
http://blog.fens.me/r-dot-product-similarity/

打赏作者

This entry was posted in R语言实践, 程序算法

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x