向量相似度算法,BM25,Jelinek-Mercer平滑
2016-05-23 14:44
337 查看
完整的来说,一下算法包括三个函数,分别是向量相似度基本算法,BM25,语言模型方法(Jelinek-Mercer平滑)或者叫线性插值LM
向量相似度基本算法公式为:
其中w表示权重,d表示文档。权重的计算公式为w=
idf为逆文档频率
BM2公式为:
均长度。
其中,k1,b为调节因子,通常根据经验设置,一般k1=2,b=0.75
语言模型方法(Jelinek-Mercer平滑)公式为:
接下来就是具体的事例和代码:
Query:Obama health plan
Document1: Obama rejects allegations about his own bad health
Document2: The plan is to visit Obama
Document 3: Obama raisesconcerns with US health plan reforms
public class VSM { public static double sim(double d[],double w[][],int k)//计算相似度 { //*d[]存的是idf同时也是每个单词在query的权重。 //*k为文档id double simi = 0,fenzi=0,fmq,fmd=0,fenmu; int i; for(i=0;i<3;i++) fenzi=fenzi+d[i]*w[i][k]; fmq=Math.sqrt(d[1]*d[1]+d[2]*d[2]); fmd=Math.sqrt(w[0][k]*w[0][k]+w[1][k]*w[1][k]+w[2][k]*w[2][k]); fenmu=fmq*fmd; simi=fenzi/fenmu; return simi; } public static double bm25(double idf[],double w[][],int n) { //*传入的n为文档id,w[][]为权重 double rsv=0,b=0.25,k,leave; int k1=2,i,ld; if(n==1) ld=6;//文档2长度为6 else ld=8;//文档1、3长度为8 leave=(8+5+8)/3;//平均文档长度 k=k1*(1-b+b*(ld/leave)); for(i=0;i<3;i++)//w[i] 为单词i在文档n中权重 rsv=rsv+idf[i]*(((k1+1)*w[i] )/(k+w[i] ));//11.32公式 return rsv; } public static void LM(int tf[][],int cf[],int t) { //*传入的tf为每个单词出现在每个文档的概率 //*传入的cf数组存储的是单词出现在文档集的次数 //*传入的t为单词出现在文档集次数的总和 double p1[]=new double [3];//用来存储p(t|mc) double p3[][]=new double [3][3];//用来存储p(t|md) double []pd={1,1,1};//初始化p(q|d) double []len={8,6,8};//文档1 2 3的内容长度 double lmd=0.5;//随便取lanmuda为0.5 int i,j; for(i=0;i<3;i++) { p1[i]=cf[i]/(double)t;//公式 //System.out.println(p1[i]); } for(i=0;i<3;i++) { for(j=0;j<3;j++) { p3[i][j]=tf[i][j]/len[j];//公式 // System.out.print(p3[i][j]+" "); } //System.out.println(); } for(i=0;i<3;i++) { for(j=0;j<3;j++) pd[i]=pd[i]*(lmd*(p3[j][i]+p1[i]));//公式 System.out.println("文档"+(i+1)+"的概率为:"+pd[i]); } } public static void main(String args[]) { String q[]=new String [3]; q[0]="Obama";q[1]="health";q[2]="plan"; String d1[][]=new String[3][8]; d1[0][0]="Obama";d1[0][1]="rejects";d1[0][2]="allegations";d1[0][3]="about";d1[0][4]="his"; d1[0][5]="own";d1[0][6]="bad";d1[0][7]="health"; d1[1][0]="The";d1[1][1]="plan";d1[1][2]="is";d1[1][3]="to";d1[1][4]="visit";d1[1][5]="Obama"; d1[2][0]="Obama";d1[2][1]="raises";d1[2][2]="concerns ";d1[2][3]="with";d1[2][4]="US"; d1[2][5]="health";d1[2][6]="plan";d1[2][7]="reforms"; //*以上为初始化query和文档,下面开始进行运算 int [][]tf =new int [3][3];//存单词在每个文档中出现的频率 double [][]w=new double [3][3];//权重 double []idf=new double [3];//逆文档频率 int i,j,k,flag; for(i=0;i<3;i++)//取q中字符串 for(k=0;k<3;k++)//取文档k { flag=0; for(j=0;j<8;j++)//取文档中的字符串 if(q[i].equals(d1[k][j])) flag++; tf[i][k]=flag; } for(i=0;i<3;i++)//计算逆文档频率 { flag=0; for(j=0;j<3;j++) if(tf[i][j]>0)//如果在这个文档出现过 flag++; idf[i]=Math.log(3.0/(double) flag); } for(i=0;i<3;i++)//计算权重 for(j=0;j<3;j++) w[i][j]=tf[i][j]*idf[i]; //*0,1,2为文档号 /*System.out.println("query和文档1的相似度为:"+sim(idf,w,0)); System.out.println("query和文档2的相似度为:"+sim(idf,w,1)); System.out.println("query和文档3的相似度为:"+sim(idf,w,2));*/ //*实验第二题的输出 /*System.out.println("文档1:"+bm25(idf,w,0)); System.out.println("文档2:"+bm25(idf,w,1)); System.out.println("文档3:"+bm25(idf,w,2));*/ ////以下为第三小题 int cf[]=new int [3]; int t=0; for(i=0;i<3;i++) { flag=0; for(j=0;j<3;j++) for(k=0;k<8;k++) if(q[i]==d1[j][k]) flag++; cf[i]=flag; t=t+cf[i]; //System.out.println(cf[i]+" "+t); } LM(tf,cf,t); } }
相关文章推荐
- 总结一下android studio的六种依赖
- Java 中char是如何编码的
- iReport专题学习之字段、参数04
- STM32的DMA
- 愿你的眼中总有光芒,活成你想要的模样!
- css 中的相对定位和绝对定位
- 理解矩阵乘法
- Delphi 中ASSERT用法
- Androi之 9patch图详解
- Matlab保留ROI区域,并将非ROI区域颜色置0
- Android上如何让TextView上的字体放大且自滚动
- action重定向
- javascript this关键字指向详解
- 滴滴算法大赛算法解决过程 - 数据分析
- df du
- java 小数点取2位并且四舍五入
- css之!important最高优先级
- V4包下SwipeRefreshLayout使用(带上拉加载更多)
- hibernat异常:Unable to get the default Bean Validation factory
- 反向传值的几种常用方法