您的位置:首页 > 其它

向量相似度算法,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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: