Jensen-Shannon散度

原创 2015年07月10日 16:18:55

        文本匹配有很多种算法,常见的如余弦相似度,杰卡德距离,TFIDF等,这些方法网上资料很多,这里就不在讲了,前段时间做工程的时候用到了JS散度,网上一查关于JS散度的资料太少,并且大多都是英文的,且没有找到算法源码,实在没办法,本人就花了一个小时左右写了一个JS散度的JAVA源码供大家参考使用。

先介绍JS散度吧,JS散度是KL散度的一种变种,其基于KL散度,但是区别于KL散度有两点: (1), JS散度的最终值域范围是[0,1],相同为0,相反为1.(例如,str1=毛主席 ,str2=毛主席, 那么因为str1与str2每个字都是相同的,故而JS(str1,str2)=0,而 str3=周总理,那么JS(str1,str3)=1)。(2),对称性(主要区别点),即JS(str1,str2)=JS(str2,str1),(因为JS相对与KL,它引入了一个变量,设为M,则M=1/2(P+Q))。

废话不多说,我们就直接上源码了,有什么问题或者不清楚的话在交流。

//注:本代码在于计算两段英文文章的JS散度,童鞋们可以根据自己的需要进行修改

package VirtualPaper;


import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


//以字符串中每个汉字所属拼音作为一个整体,js距离是相同的则为0,不相同的则为1


public class JensenShannonUnit {



//得到字符串的概率分布--以一个汉字拼音作为一个整体
public HashMap<String,Double> getDistribution(String str){
HashMap<String,Integer> map = new HashMap<String,Integer>();      //存储子字符串,及其出现的次数
HashMap<String,Double> mappro = new HashMap<String,Double>();        //存储子字符串的概率分布

String[] str11 = str.split(" ");
int total = str11.length;                           //字符串数组的长度(含有的子字符串的个数)

for(String word : str11){                   //将字母存入HashMap中
if(map.containsKey(word)){
int value = map.get(word);
map.put(word, ++value);
}else
map.put(word, 1);
}

Set<String> set = map.keySet();
for(String word:set){
int value = map.get(word);
double probility = value*1.0/total;
mappro.put(word, probility);
}

//System.out.println(mappro);
return mappro;
}

//得到1/2(P+Q)的分布
public Map<String,Double> getM(Map<String,Double> map1,Map<String,Double> map2){
Map<String,Double> map = new HashMap<String,Double>();           //存储1/2(P+Q)的概率分布

Set<String> set1 = map1.keySet();
Set<String> set2 = map2.keySet();
//将所有的字符添加至一个 set里面
Set<String> set = new HashSet<String>();
set.addAll(set1);
set.addAll(set2);

for(String word:set){             //得到value1和value2的平均值
double i = 0;          //P的单词概率
double j = 0;   //Q的单词概率
if(map1.containsKey(word))
i = map1.get(word);
if(map2.containsKey(word))
j = map2.get(word);
double min = (i+j)/2;
map.put(word, min);
}

return map;
}

//得到两个HashMap的KL距离  map1为P或Q,map2为M=1/2(P+Q)
public double getKLDistance(Map<String,Double> P,Map<String,Double> M){
double KLD = 0;
Set<String> set1 = P.keySet();
//Set<Character> set2 = map2.keySet();
for(String ch:set1){
double i = P.get(ch);
double j = M.get(ch);
double m = i*(Math.log(i/j)/Math.log(2));    //以底为2的对数函数
KLD+=m;
}
return KLD;
}


public double getJensenDistance(String str1,String str2){
Map<String,Double> P = getDistribution(str1);
Map<String,Double> Q = getDistribution(str2);
Map<String,Double> M = getM(P, Q);

double KLDP = getKLDistance(P, M); 
double KLDQ = getKLDistance(Q, M);
double jsd = (KLDP+KLDQ)/2;

return jsd;
}
}

有问题的话 大家多讨论,也顺便贴出较简单的Cos相似度和杰卡德系数

package VirtualPaper;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;


public class JaccardAndCosUnit {

//计算两个字符串的Jaccard系数--一个中文字体的拼音作为一个单元
public double getJaccard(String str1,String str2){
String[] str11=str1.split(" ");
String[] str22=str2.split(" ");
Set<String> intersection=new HashSet<String>();
Set<String> union=new HashSet<String>();

for(int i=0;i<str11.length;i++){
for(int j=0;j<str22.length;j++){
if(str11[i].equals(str22[j]))
intersection.add(str11[i]);
else{
union.add(str11[i]);
union.add(str22[j]);
}
}
}

/* System.out.println("交集大小:"+intersection.size());
System.out.println("并集大小:"+union.size());*/
return (double)intersection.size()/union.size();
}





//计算余弦相似度  向量值表示出现的次数
//得到字符串的向量表示
public List<Integer> getVectors(Set<String> set,String str){
List<Integer> list=new ArrayList<Integer>();         //存储向量值
TreeMap<String,Integer> treemap=new TreeMap<String,Integer>(); 
for(String word:set){
treemap.put(word, 0);
}

String[] str11 = str.split(" ");
for(int i=0;i<str11.length;i++){
int frequency=treemap.get(str11[i]);
treemap.put(str11[i],frequency+1);
}


Iterator<Integer> iter=treemap.values().iterator();
while(iter.hasNext()){
list.add(iter.next());
}
return list;
}
//计算余弦相似度
public double compcos(List<Integer> list1,List<Integer> list2){
double ab=0;             //存储两个向量的积
for(int i=0;i<list1.size();i++){
ab+=list1.get(i)*list2.get(i);
}
double a=0;
for(Integer in:list1){
a+=Math.pow(in, 2);
}
double b=0;
for(Integer in:list2){
b+=Math.pow(in, 2);
}
return ab/Math.sqrt(a*b);      //返回余弦相似度
}

//计算两个字符串的余弦相似度
public double getCosstr(String str1,String str2){
Set<String> hashset=new HashSet<String>();  //存储两个字符串的子字符串并集合
String[] str11 = str1.split(" ");
String[] str22 = str2.split(" ");
for(int i=0;i<str11.length;i++){
hashset.add(str11[i]);
}
for(int i=0;i<str22.length;i++){
hashset.add(str22[i]);
}
//将字符串用向量进行表示
List<Integer> list1=getVectors(hashset,str1);
List<Integer> list2=getVectors(hashset,str2);
//返回两个向量的余弦相似度
return compcos(list1,list2);
}
}

欢迎大家支出错误!

相关文章推荐

信息论——JS散度(Jensen-Shannon)

JS散度相似度衡量指标。现有两个分布P1P_1和P2P_2,其JS散度公式为: JS(P1||P2)=12KL(P1||P1+P22)+12KL(P2||P1+P22)JS(P_1||P_2)=\f...

令人拍案叫绝的Wasserstein GAN

原文地址:https://zhuanlan.zhihu.com/p/25071913  作者:郑华滨 在GAN的相关研究如火如荼甚至可以说是泛滥的今天,一篇新鲜出炉的arXiv论文《Wassers...

python实现:KL距离、jensen-shannon距离

Kullback–Leibler divergence:两个概率分布之间的距离,是从信息熵的角度出发,也叫鉴别信息。 计算公式:          对于所有i,都有Q(i)=0 implies ...

相对熵(KL散度)

今天开始来讲相对熵,我们知道信息熵反应了一个系统的有序化程度,一个系统越是有序,那么它的信息熵就越低,反 之就越高。下面是熵的定义   如果一个随机变量的可能取值为,对应的概率为,则随机变 量的熵定义...

kl距离(散度)&l1范数区别

详细讲解 l0 l1 l2 范数,稀疏,规范化 http://blog.csdn.net/zouxy09/article/details/24971995 http://ufldl.stanford....

Wasserste GAN理解

原文:发布者: 炼数成金_小数  原作者: Gapeng GAN回顾 Martin 称这个loss为original cost function(参见[1] 2.2.1...

极坐标系下的散度(场论)

  • 2014年04月09日 00:06
  • 281KB
  • 下载

散度计算的MATLAB代码

  • 2016年03月15日 21:38
  • 696B
  • 下载

差分熵与Kullback–Leibler散度

一、差分熵(Differential Entropy) 我们已经在另外一篇文章(http://blog.csdn.net/baimafujinji/article/details/6...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Jensen-Shannon散度
举报原因:
原因补充:

(最多只允许输入30个字)