定义:计算个体间的相似程度,相似度值越小,相似距离越大。
最常用:余弦相似度 -> 两个向量夹角的余弦值,余弦值为1,夹角为0,越相似
为什么不用欧氏距离:
余弦相似度值域在-1到1,欧氏距离在0到无穷大,究竟多大算大?没有度量标准
余弦相似度衡量的是维度间取值方向的一致性,注重维度之间的差异,不注重数值上的差异,而欧氏度量的正是数值上的差异性。
注解:
a与b在实际意义上是相似的,都是喜欢第一部与第五部,只是打分的极端性不同,如果使用欧氏距离,a与b的距离是比较大的,即说明了上面那句:余弦相似度衡量的是维度间取值方向的一致性,注重维度之间的差异,不注重数值上的差异。
二:(实践部分):求句子的词频向量并求余弦相似度 step1:切词(借助Jieba库) ## 1.切词 s1_seg = [x for x in jieba.cut(s1) if x!=''] s2_seg = [x for x in jieba.cut(s2) if x!=''] print(s1_seg) print(s2_seg) 2.去除停用词并得到词典 #2.传入所需计算的列表 # 去除停用词 # 返回词典 def get_word_dict(*l): # 读取停用词txt word_dict=[] stop_list=set() with open('stop_word/中文停用词表.txt', 'r',encoding='utf-8') as f: for word in f.readlines(): stop_list.add(word.strip()) for t in l: for v in t: if v not in stop_list: word_dict.append(v) word_dict=list(set(word_dict)) return word_dict 3.根据词典生成原始句子的词向量 def get_word_vec(l,dict): vec = [0]*len(dict) for v in l: if v in dict: index=dict.index(v) vec[index]+=1 return vec 4.求余弦值 def cosVector(x,y): if(len(x)!=len(y)): print('error input,x and y is not in the same space') return; result1=0.0; result2=0.0; result3=0.0; for i in range(len(x)): result1+=x[i]*y[i] #sum(X*Y) result2+=x[i]**2 #sum(X*X) result3+=y[i]**2 #sum(Y*Y) return result1/((result2*result3)**0.5) 三:TFIDFTF(term frequency)词频可以很好的反应这个词出现的次数,但是还会存在一种状况:这个词频率很高但是在大多数文档里都出现了,因此也不能作为权重很高的代表,因此IDF(反文档频率)可以降低这种情况的影响。
按词频*反文档频率值排序,即可得出这篇文章的关键词。
例如:
词频的两种常见求法:
选用第二种(频率分布较为均匀,第一种基本数值很小,但是第一种和为1): def dict_to_TF_dict(dict): # 字典依照value排序 TF_dict={} dict = sorted(dict.items(), key=lambda x: x[1], reverse=True) max = dict[0][1] for v in dict: TF_dict[v[0]]= v[1]/max return TF_dict #接收一篇文章去重后的set集合 def set_to_IDF(res_no_repeat): IDF_dict={} for filename in os.listdir('allfiles'): no_stop_list = convert_to_list_with_not_stop_word('allfiles/' + filename, 1) for v in no_stop_list: if v in res_no_repeat: if (IDF_dict.get(v) == None): IDF_dict[v] = 0 IDF_dict[v] += 1 for v in IDF_dict.keys(): IDF_dict[v] = math.log(len(os.listdir('allfiles')) / (IDF_dict[v] + 1)) return IDF_dict
结果:
计算相似文章的方法