轉自:http://www.chepoo.com/cosine-similarity-java-implementation.html
文章相似度的實現(xiàn)可以用余弦相似性實現(xiàn)。余弦定理可參考:
字符串之間的相似度實現(xiàn):字符串相似度算法(編輯距離)java實現(xiàn)
我們可以把它們想象成空間中的兩條線段,都是從原點([0, 0, ...])出發(fā),指向不同的方向。兩條線段之間形成一個夾角,如果夾角為0度,意味著方向相同、線段重合;如果夾角為90度,意味著形成直角,方向完全不相似;如果夾角為180度,意味著方向正好相反。因此,我們可以通過夾角的大小,來判斷向量的相似程度。夾角越小,就代表越相似。
余弦值越接近1,就表明夾角越接近0度,也就是兩個向量越相似,這就叫”余弦相似性”。
阮一峰老師寫的一篇博文簡單明了,大家可以看看:TF-IDF與余弦相似性的應用(二):找出相似文章
實現(xiàn)該算法思路:
1.先用es-ik進行文章分詞。
2.得到兩篇文章的詞頻向量
3.計算兩個向量的余弦相似度,值越大就表示越相似。
相關代碼實現(xiàn)已經(jīng)github上。具體地址為:https://github.com/awnuxkjy/recommend-system
package com.xq.algorithm;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
* <p>Title:</p>
* <p>Description: 余弦獲取文章相似性
* </p>
* @createDate:2013-8-26
* @author xq
* @version 1.0
*/
public class CosineSimilarAlgorithm {
/**
*
* @Title: cosSimilarityByFile
* @Description: 獲取兩個文件相似性
* @param @param firstFile
* @param @param secondFile
* @param @return? ?
* @return Double?
* @throws
*/
public static Double cosSimilarityByFile(String firstFile,String secondFile){
try{
Map<String, Map<String, Integer>> firstTfMap=TfIdfAlgorithm.wordSegCount(firstFile);
Map<String, Map<String, Integer>> secondTfMap=TfIdfAlgorithm.wordSegCount(secondFile);
if(firstTfMap==null || firstTfMap.size()==0){
throw new IllegalArgumentException("firstFile not found or firstFile is empty! ");
}
if(secondTfMap==null || secondTfMap.size()==0){
throw new IllegalArgumentException("secondFile not found or secondFile is empty! ");
}
Map<String,Integer> firstWords=firstTfMap.get(firstFile);
Map<String,Integer> secondWords=secondTfMap.get(secondFile);
if(firstWords.size()<secondWords.size()){
Map<String, Integer> temp=firstWords;
firstWords=secondWords;
secondWords=temp;
}
return calculateCos((LinkedHashMap<String, Integer>)firstWords, (LinkedHashMap<String, Integer>)secondWords);
}catch(Exception e){
e.printStackTrace();
}
return 0d;
}
/**
*
* @Title: cosSimilarityByString
* @Description: 得到兩個字符串的相似性
* @param @param first
* @param @param second
* @param @return? ?
* @return Double?
* @throws
*/
public static Double cosSimilarityByString(String first,String second){
try{
Map<String, Integer> firstTfMap=TfIdfAlgorithm.segStr(first);
Map<String, Integer> secondTfMap=TfIdfAlgorithm.segStr(second);
if(firstTfMap.size()<secondTfMap.size()){
Map<String, Integer> temp=firstTfMap;
firstTfMap=secondTfMap;
secondTfMap=temp;
}
return calculateCos((LinkedHashMap<String, Integer>)firstTfMap, (LinkedHashMap<String, Integer>)secondTfMap);
}catch(Exception e){
e.printStackTrace();
}
return 0d;
}
/**
*
* @Title: calculateCos
* @Description: 計算余弦相似性
* @param @param first
* @param @param second
* @param @return? ?
* @return Double?
* @throws
*/
private static Double calculateCos(LinkedHashMap<String, Integer> first,LinkedHashMap<String, Integer> second){
List<Map.Entry<String, Integer>> firstList = new ArrayList<Map.Entry<String, Integer>>(first.entrySet());
List<Map.Entry<String, Integer>> secondList = new ArrayList<Map.Entry<String, Integer>>(second.entrySet());
//計算相似度?
? ? ? ? double vectorFirstModulo = 0.00;//向量1的模?
? ? ? ? double vectorSecondModulo = 0.00;//向量2的模?
? ? ? ? double vectorProduct = 0.00; //向量積?
? ? ? ? int secondSize=second.size();
for(int i=0;i<firstList.size();i++){
if(i<secondSize){
vectorSecondModulo+=secondList.get(i).getValue().doubleValue()*secondList.get(i).getValue().doubleValue();
vectorProduct+=firstList.get(i).getValue().doubleValue()*secondList.get(i).getValue().doubleValue();
}
vectorFirstModulo+=firstList.get(i).getValue().doubleValue()*firstList.get(i).getValue().doubleValue();
}
? return vectorProduct/(Math.sqrt(vectorFirstModulo)*Math.sqrt(vectorSecondModulo));
}
public static void main(String[] args){
Double result=cosSimilarityByString("中國是超級大國",
"中國是世界超級大國。");
System.out.println(result);
}
}