1. 程式人生 > >基於編輯距離來判斷詞語相似度方法(scala版)

基於編輯距離來判斷詞語相似度方法(scala版)

使用 ref ray 只需要 art 算法 位置 spark else

詞語相似性比較,最容易想到的就是編輯距離,也叫做Levenshtein Distance算法。在Python中是有現成的模塊可以幫助做這個的,不過代碼也很簡單,我這邊就用scala實現了一版。

編輯距離

編輯距離是指一個字符串改編成另一個字符串的最短距離,它描述了兩個字符串的相近程度。比如:

son -> sun ,只需要把o改成u即可,編輯距離為1
xing -> long,需要把x改成l,i改成o,編輯距離為2
o->long,需要在前面加上l,在後面加上ng,編輯距離為3

因此所有修改,移動,刪除,新增都算是一次編輯操作。

算法很簡單:

初始化

- x i n g
- 0 1 2 3
l 1 0 0 0
o 2 0 0 0
n 3 0 0 0
g 4 0 0 0

挨個計算值

某個位置的值,等於它

  • 左邊的值+1,
  • 右邊的值+1,
  • 左上角的值不同時加1;相同時加0

上面三個數的最小值

- x i n g
- 0 1 2 3
l 1 1 0 0
o 2 0 0 0
n 3 0 0 0
g 4 0 0 0

一直計算到右下角的值

- x i n g
- 0 1 2 3
l 1 1 2 3
o 2 2 2 3
n 3 3 3 2
g 4 4 4 3

Breeze

在python中有numpy可以做矩陣的各種操作,在scala中可以使用breeze,spark mllib底層也是基於它實現的。

文檔參考:
https://github.com/scalanlp/breeze/wiki/Quickstart

常用的操作有:

創建為0的的矩陣:
DenseMatrix.zeros[Int](s1_length, s2_length)

breeze另一個很好用的地方就是默認支持修改,在scala中很多集合默認都是不可變的,比如Array,很煩~

算法實現

def editDist(s1:String, s2:String):Int ={
   val s1_length = s1.length+1
   val s2_length = s2.length+1

   val matrix = DenseMatrix.zeros
[Int](s1_length, s2_length) for(i <- 1.until(s1_length)){ matrix(i,0) = matrix(i-1, 0) + 1 } for(j <- 1.until(s2_length)){ matrix(0,j) = matrix(0, j-1) + 1 } var cost = 0 for(j <- 1.until(s2_length)){ for(i <- 1.until(s1_length)){ if(s1.charAt(i-1)==s2.charAt(j-1)){ cost = 0 }else{ cost = 1 } matrix(i,j)=math.min(math.min(matrix(i-1,j)+1,matrix(i,j-1)+1),matrix(i-1,j-1)+cost) } } matrix(s1_length-1,s2_length-1) }

應用的場景

這種詞語之間的編輯距離主要應用在兩個文本判斷是否相近,比如我輸入一個詞,想要查找到數據庫裏面跟他最匹配的詞。比如阿迪想要匹配到阿迪達斯,或者結賬買單匹配到節帳埋單等等。不過在耐克nikenike耐克這種場景下就不適合了...

後續會介紹n-gram來計算相似性的方法,比較適合這種場景。

基於編輯距離來判斷詞語相似度方法(scala版)