學習筆記--NLP文字相似度之LCS(最長公共子序列)
阿新 • • 發佈:2018-12-16
最長公共子序列
一個序列S任意刪除若干個字元得到的新序列T,則T叫做S的子序列
兩個序列X和Y的公共子序列中,長度最長的那個,定義為X和Y的最長公共子序列
例如:
--字串12455與245576的最長公共子序列為2455
--字串acdfg與adfc的最長公共子序列為adf
--字串ABCBDAB與BDCABA的最長公共子序列為BCAB或BCBA或BDAB
LCS的作用
- 生物學家常利用該演算法進行基因序列比對,以推測序列的結構、功能和演化過程。
- 描述兩段文字之間的“相似度”
- 辨別抄襲,對一段文字進行修改之後,計算改動前後文字的最長公共子序列,將除此子序列 外的部分提取出來,該方法判斷修改的部分(論文查重)
LCS方法
- 暴力窮舉法(複雜度高,不可用!)
- 動態規劃法
資料結構(二維陣列)
--- 當i=0或j=0時,空序列是X 和Y 的最長公共子序列,故C[i,j]=0 ij
- 使用二維陣列C[m,n]
- C[i,j]記錄序列X 和Y 的最長公共子序列的長度
例子:
- X = <A,B,C,,B,D,A,B>
- Y = <B,D,C,A,B,A>
最長公共子序列為:BCAB、BCBA、BDAB (3個最長公共子序列,長度為4)
相似度=4*2/(6+7)=0.61
實踐:
利用MR框架來算LCS文字相似度
首先元資料為
run.sh
HADOOP_CMD="/usr/local/src/hadoop-2.6.1/bin/hadoop" STREAM_JAR_PATH="/usr/local/src/hadoop-2.6.1//share/hadoop/tools/lib/hadoop-streaming-2.6.1.jar" INPUT_FILE_PATH_1="/lcs_input.data" OUTPUT_PATH="/lcs_output" $HADOOP_CMD fs -rmr -skipTrash $OUTPUT_PATH # Step 1. $HADOOP_CMD jar $STREAM_JAR_PATH \ -input $INPUT_FILE_PATH_1 \ -output $OUTPUT_PATH \ -mapper "python map.py" \ -jobconf "mapred.reduce.tasks=0" \ -jobconf "mapred.job.name=mr_lcs" \ -file ./map.py
map.py
# -*- coding: utf-8 -*-
#!/usr/bin/python
import sys
def cal_lcs_sim(first_str, second_str):
len_vv = [[0] * 50] * 50
first_str = unicode(first_str, "utf-8", errors='ignore')
second_str = unicode(second_str, "utf-8", errors='ignore')
len_1 = len(first_str.strip())
len_2 = len(second_str.strip())
for i in range(1, len_1 + 1):
for j in range(1, len_2 + 1):
if first_str[i - 1] == second_str[j - 1]:
len_vv[i][j] = 1 + len_vv[i - 1][j - 1]
else:
len_vv[i][j] = max(len_vv[i - 1][j], len_vv[i][j - 1])
return float(float(len_vv[len_1][len_2] * 2) / float(len_1 + len_2))
for line in sys.stdin:
ss = line.strip().split('\t')
if len(ss) != 2:
continue
first_str = ss[0].strip()
second_str = ss[1].strip()
sim_score = cal_lcs_sim(first_str, second_str)
print '\t'.join([first_str, second_str, str(sim_score)])
通過MR框架跑出來的資料為