文本相似度的检测

该项目通过词频统计和余弦相似度计算文本相似度。步骤包括分词、去停用词、构建词频向量。对于词频向量,确保一致性并计算余弦相似度。还提到了IDF(逆文档频率)在权重计算中的应用,并提供了GBK到UTF8的转换方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目原理

基于词频:统计文章中词频,构建词频特征向量,利用特征向量夹角的余弦值表示文本的相似度。两篇文章最大相似度为1,特征向量夹角为0°。
基于词频的文本相似度检测步骤:

  1. 文本1和文本2
  2. 分词—去停用词
  3. 统计两篇文章的词频
  4. 词频向量1和词频向量2
  5. 相似度的计算
  • 分词:例:“我是一个学生” 分词后为“我//是//一个//学生”
  • 去停用词 分词后可发现有很多词是没有实际含义的功能性词,例如“我” 、“怎么办”、“总之”。因此分词后不能直接对词频进行统计,应先去掉停用词后,再对词频进行统计。
  • 词频 单词在文章中出现的次数,词频越大,可以认为该词越重要
  • 词频向量在构建词频向量时,需要考虑向量的意义,也必须保障向量的一致性,即两个文本向量每一维的值应该代表的是同一个词的词频。
    例:
    文档1 今天//有事//,//没办法//去//学校//上课//了
    文档2 真想//去//学校//上课//,//但是//今天//有事//,//去不了//学校//了
    去掉停用词后
    文档1中的词频:[有事1,没办法1,去1,学校1,上课1]
    文档2中的词频:[真想1,去1,学校2,上课1,有事1,去不了1]
    直接用上述词频构建每一个文本的词频向量是无意义的,因为每一维表示的意思均不同,因此需构建一致的词频向量。
    将所有的有效词结合起来构建[学校,去,真想,上课,有事,去不了,没办法]
    计算词频向量:
    文档1 :[1,1,0,1,1,0,1] 文档2:[2,1,1,1,1,1,0]
  • 向量相似度 采用余弦相似度
    采用余弦相似度
    在TextSimilarity类中对各个接口进行声明
class TextSimilarity
{
   
public:
	typedef std::unordered_map<std::string, double> WordFrep;//词频
	typedef std::unordered_set<std::string> WordSet;//词表
	typedef std::pair<std::string, double> PSI;//键值对
	TextSimilarity(const char* dictPach);//构造函数
	TextSimilarity(Config& cfg);
	void printStopWordSet();//打印停用词表
	void printWordFrep(const WordFrep& wordFreq);//打印词频
	double getTextSimilarity(const char* file1, const char* file2);//提供获取文本相似度的接口

//private: 
    //获取停用词表
	void getStopWordSet(const char*file);
    //获取IDF(逆文档率),表示每个词重要性的权重
	void getIDF(const char* file);
	//统计词频: word   num(map中序遍历是有序的,本身是无序的)
	//项目本身需要Value有序,但map不支持,所以使用无序的map,效率较高
	void getWordFrep(const char* file, WordFrep& wordFreq);
	//统计相对词频,单词词频/文章单词总数
	void getNormalizedWordFrep(WordFrep& wordFreq);
	//统计加入IDF权重的词频
	void getTfIdf(WordFrep& wordFreq, WordFrep& outTfIdf);
	//GBK转UTF8
	std::string GBK2UTF8(const std::string& gbk);
	//UTF8转GBK
	std::string UTF82GBK(const std::string& utf8);
	//根据Value值进行排序
	void sortReverseByValue(const WordFrep& wordFreq, std::vector<PSI>& outSortedWordFreq);
	//构建统一的词表
	void getWordCode(std::vector<PSI>& inSortWordFreq, WordSet& wordCode);
	//根据词表,创建词频向量
	void getVector(WordSet& wordCode, WordFrep& wordFreq, std::vector<double>& outVec);
	//计算文本相似度
	double getCosine(std::vector<double>& vec1, std::vector<double>& vec2);

	//分词对象成员
	std::string DICT_PATH;//词典路径
	cppjieba::Jieba _jieba;//分词对象
	

	//停用词表,只需要存放停用词,用string(字符串)来存储,给一个哈希表
	WordSet _stopWordSet;
	int _maxWordNum;
	WordFrep _Idf;
};

成员变量有5个,分别是分词的词典路径,分词对心,停用词表,构建统一词表的最大个数_maxWordNum,以IDF方式计算的词频_Idf;

IDF(Inverse Document Frequency): 逆文档率,它表示每一个词重要性的权重,一个词越少见,它的值就越大,反之,一个词越常见,它的值就越小。
下面分别实现各个接口的功能:

//构造函数:
TextSimilarity::TextSimilarity(const char* dictPach)
	:DICT_PATH(dictPach)
	, _jieba(
	DICT_PATH + "/jieba.dict.utf8"
	, DICT_PATH + "/hmm_model.utf8"
	, DICT_PATH + "/user.dict.utf8"
	, DICT_PATH + "/idf.utf8"
	, DICT_PATH + "/stop_words.utf8"
	)
	, _maxWordNum(20)//统一的词表最大的个数,初始化为20
{
    
	std::string stopFileDir = DICT_PATH + "/stop_words.utf8";
	getStopWordSet(stopFileDir.c_str());
	getIDF((DICT_PATH + "/idf.utf8").c_str());
}

//获取停用词,填充在对象_stopWordSet中
void TextSimilarity::getStopWordSet
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值