基于字的文本相似度算法——余弦定理

一、算法原理

  基于字的文本相似度余弦定理算法的原理是:

(1)分别统计两个比较文本中所有字出现的频率,从而得出两个文本对应的向量
(2)利用余弦定理计算这两个向量的夹角余弦值

(3)根据自设置的阈值判断两个文本是否相似


二、算法的C++实现

这里引用的StringUtil.hpp文件引自:

https://github.com/yanyiwu/cppjieba/blob/master/deps/limonp/StringUtil.hpp


/*
 * CosineSimilarity.hpp
 *
 *  Created: 2016年10月2日
 *   Author: tang
 */

#ifndef SRC_COSINE_SIMILARITY_HPP_
#define SRC_COSINE_SIMILARITY_HPP_
#include <iostream>
#include <vector>
#include <map>
#include <math.h>
#include "StringUtil.hpp"

using namespace std;

class CosineSimilarity
{
public:
	CosineSimilarity()
	{
	}

	double CalculateTextSimilarity(string &str1,string &str2)
	{
		vector<uint16_t> words_for_str1;
		vector<uint16_t> words_for_str2;
		vector<uint16_t>::iterator it;

		if(!utf8ToUnicode< vector<uint16_t> >(str1,words_for_str1) || 
			!utf8ToUnicode< vector<uint16_t> >(str2,words_for_str2 ) )
		{
			cout<<"TransCode Error"<<endl;
			return 0.;
		}

		map< uint16_t,pair<int,int> >seq_map;
		map< uint16_t,pair<int,int> >::iterator map_it;
		for(it=words_for_str1.begin();it!=words_for_str1.end();++it)
		{
			if(isHanzi(*it))
			{
				map_it=seq_map.find(*it);
				if(map_it!=seq_map.end())
				{
					map_it->second.first++;
				}
				else
				{
					pair<int,int> seq;
					seq.first=1;
					seq.second=0;
					seq_map[*it]=seq;
				}
			}
		}

		for(it=words_for_str2.begin();it!=words_for_str2.end();++it)
                {
			if(isHanzi(*it))
                        {
                                map_it=seq_map.find(*it);        
                                if(map_it!=seq_map.end())
                                {
                                        map_it->second.second++;
                                }
                                else
                                {
					pair<int,int> seq;
                                        seq.first=0;
                                        seq.second=1;
                                        seq_map[*it]=seq;
                                }
                        }
                }

		double sqdoc1 = 0.;  
               	double sqdoc2 = 0.;  
               	double denominator = 0.;

		for(map_it=seq_map.begin();map_it!=seq_map.end();++map_it)
		{
			pair<int,int> c=map_it->second;
			denominator +=(c.first * c.second);
			sqdoc1+=(c.first * c.first);
			sqdoc2+=(c.second * c.second);
		} 

		if(0==sqdoc1 * sqdoc2)
			return -1.0;

		return denominator/sqrt(sqdoc1 * sqdoc2);
	}

	bool codeFilter(int code) 
	{
        	if ((code < 0x4e00 || code > 0x9fa5) && 
			!(code >= '0' && code <= '9') && 
			!(code >= 'a' && code <= 'z') && 
			!(code >= 'A' && code <= 'Z'))
           		 return false;
        
        	return true;
	}

	bool isHanzi(uint16_t ch)
	{
		return (ch >= 0x4E00 && ch <= 0x9FA5);
	}
};

三、算法的Java实现

import java.io.UnsupportedEncodingException;  
import java.util.Date;  
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map; 


public class CosineSimilarity{
    
	/**
	 * 输入两段文本利用孜频率的余弦定理判断二者间的相似度
	 * 
	 * @param doc1,文本1
	 * @param doc2,文本2
	 * @return 相似度值
	 */
    public double CalculateTextSim(String doc1, String doc2) {
		if (doc1 != null && doc1.trim().length() > 0 && doc2 != null
				&& doc2.trim().length() > 0) {
			
			Map<Integer, int[]> AlgorithmMap = new HashMap<Integer, int[]>();
			
			//将两个字符串中的中文字符以及出现的总数封装到,AlgorithmMap中
			for (int i = 0; i < doc1.length(); i++) {
				char d1 = doc1.charAt(i);
				if(isHanZi(d1)){
					int charIndex = getGB2312Id(d1);
					if(charIndex != -1){
						int[] fq = AlgorithmMap.get(charIndex);
						if(fq != null && fq.length == 2){
							fq[0]++;
						}else {
							fq = new int[2];
							fq[0] = 1;
							fq[1] = 0;
							AlgorithmMap.put(charIndex, fq);
						}
					}
				}
			}

			for (int i = 0; i < doc2.length(); i++) {
				char d2 = doc2.charAt(i);
				if(isHanZi(d2)){
					int charIndex = getGB2312Id(d2);
					if(charIndex != -1){
						int[] fq = AlgorithmMap.get(charIndex);
						if(fq != null && fq.length == 2){
							fq[1]++;
						}else {
							fq = new int[2];
							fq[0] = 0;
							fq[1] = 1;
							AlgorithmMap.put(charIndex, fq);
						}
					}
				}
			}
			
			Iterator<Integer> iterator = AlgorithmMap.keySet().iterator();
			double sqdoc1 = 0;
			double sqdoc2 = 0;
			double denominator = 0; 
			while(iterator.hasNext()){
				int[] c = AlgorithmMap.get(iterator.next());
				denominator += c[0]*c[1];
				sqdoc1 += c[0]*c[0];
				sqdoc2 += c[1]*c[1];
			}
			
			return denominator / Math.sqrt(sqdoc1*sqdoc2);
		} else {
			throw new NullPointerException("the Document is null or have not cahrs!!");
		}
    }

	/**
	 * 输入一个字符判断是否为中文汉字
	 * 
	 * @param ch,字符
	 * @return true为中文汉字,否则为false
	 */	
    public boolean isHanZi(char ch) {
	return (ch >= 0x4E00 && ch <= 0x9FA5);    
    }	
	
	/**
	 * 根据输入的Unicode字符,获取它的GB2312编码或者ascii编码,
	 * 
	 * @param ch,输入的GB2312中文字符或者ASCII字符(128个)
	 * @return ch在GB2312中的位置,-1表示该字符不认识
	 */
	public static short getGB2312Id(char ch) {
		try {
			byte[] buffer = Character.toString(ch).getBytes("GB2312");
			if (buffer.length != 2) {
				// 正常情况下buffer应该是两个字节,否则说明ch不属于GB2312编码,故返回'?',此时说明不认识该字符
				return -1;
			}
			int b0 = (int) (buffer[0] & 0x0FF) - 161; // 编码从A1开始,因此减去0xA1=161
			int b1 = (int) (buffer[1] & 0x0FF) - 161; // 第一个字符和最后一个字符没有汉字,因此每个区只收16*6-2=94个汉字
			return (short) (b0 * 94 + b1);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return -1;
	}
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的文本相似度可以通过基于TF-IDF和余弦相似度算法来实现。TF-IDF(Term Frequency-Inverse Document Frequency)是用于评估一个词语在一个文档中的重要程度的方法。 首先,我们需要使用Python中的文本处理库(如nltk)来对文本进行预处理,包括分词、去除停用词、词干化等。接下来,我们可以使用sklearn库中的TF-IDF向量化器来将文本转换为TF-IDF特征向量。 然后,我们可以使用余弦相似度算法来计算两个文本之间的相似度余弦相似度是通过计算两个向量之间的夹角来度量它们的相似程度的。 以下是一个简单的示例代码: ```python import nltk from nltk.corpus import stopwords from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity def preprocess_text(text): # 分词 tokens = nltk.word_tokenize(text) # 去除停用词 stop_words = set(stopwords.words('english')) tokens = [token for token in tokens if token.lower() not in stop_words] # 词干化 stemmer = nltk.PorterStemmer() tokens = [stemmer.stem(token) for token in tokens] # 返回处理后的文本 return " ".join(tokens) def calculate_similarity(text1, text2): # 预处理文本 processed_text1 = preprocess_text(text1) processed_text2 = preprocess_text(text2) # 转换为TF-IDF特征向量 vectorizer = TfidfVectorizer() tfidf_matrix = vectorizer.fit_transform([processed_text1, processed_text2]) # 计算余弦相似度 cosine_sim = cosine_similarity(tfidf_matrix[0], tfidf_matrix[1]) # 返回相似度 return cosine_sim[0][0] text1 = "今天天气不错" text2 = "今天天气很好" similarity = calculate_similarity(text1, text2) print("文本1和文本2的相似度为:", similarity) ``` 在以上示例中,我们先对文本进行了预处理,并使用TF-IDF向量化器将其转换为特征向量。然后,我们使用余弦相似度算法计算了文本1和文本2之间的相似度,并输出结果。 这只是一个简单的示例,实际应用中可能需要更多的预处理步骤和参数调整来获得更好的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值