项目:文本相似度分析(C++)

项目源码https://github.com/zhangyi-13572252156/-.git

文本相似度分析

  • 简介:基于jieba 分词第三方库。
  • jieba 库地址:https://github.com/fxsjy/jieba.git
  • 简单的介绍一下 jieba 第三方库所用到的算法。
    • 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG)
    • 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合
    • 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法
  • 我主要是用这个库来实现文本的精确分词,接着拿到这些词的出现的频率,构建基于词频的特征向量。通过特征向量借助多种算法来求文本相似度。
  • 注意:我们要知道,在linux下编码方式是UTF-8的,但是在windows下编码方式是GBK的。但是jieba 分词只支持UTF-8编码方式,因此我在windows下VS中使用jieba 时,要先将词的编码方式进行转换。前期我在做的时候特别纳闷,后来才知道是编码方式的问题。

思路分析

  • 第一步是文本分词,我们已经说过,我们借助jieba 这个第三方库对文本进行词频划分。使用jieba 的精确分词模式。
  • 第二步是去停用词,我们都知道我们中文中的一句话,可能有很多词是没有实际含义的。
    • 比如像人类语言包含很多功能词。与其他词相比,功能词没有什么实际含义。 停用词主要包括数字、标点符号及使用频率特高的词(代词,语气助词、副词、介词、连接词 )等。
我
我们
怎么办
总之
此外 然而 不如 不妨 。 , ?
........
-  停用词不代表实际意义,所以不需要统计停用词的词频,停用词不参与构建词频向量
  • 第三步构建词频向量,词频即为单词在文章中出现的次数。词频的大小一般可以反映一个词在一篇文章中的重要性,词频越大,可以认为该词越重要。
    一片文章的语义可以由一组关键词简要概括,

    • 比如"今天早上八点钟,我要去上课",关键词"八点,上课"。
    • 分词编码 : 在构建文本词频向量时,需要考虑向量的意义,也必须保证向量的一致性,这样才有可比性。
    • 意义:文本的语义,用词频来表示一致性:如何保证一致性?向量中的每一维值都应该表示相同的意思。更具体的说,一致性就体现在两个文本向量的每一维都应该表示同一个词的词频。
  • 第四步运用多种算法进行向量的相似度分析。有关大佬总结的文本相似度分析的博文,很有必要参考一下。https://cloud.tencent.com/developer/article/1038872

文本相似度算法

  • 我还是来扯一下几种算法
    分词 + 杰卡德系数
    • 他是最简单的算法,很粗暴的算法。为了对比两个东西的相似度,我们很容易就想到可以看他们之间有多少相似的内容,又有多少不同的内容,再进一步可以想到集合的交并集概念。
    • 假设有两个集合A,B;如果我们想要知道这两个集合的相似度究竟有多少,我们可以进行这样的计算,两个文本词的交集除以两个文本词的并集。越大表明两个集合的相似度越高。
    • 这个算法的计算效率最高、最快。不过因为公式太简单,能涵盖到的维度太少,所以在需要比较高准度的场合并不适用。当然如果要判断的文本不存在语义等复杂问题要考虑,量又比较大的话,还是个非常不错的选择。
      这个算法比较简单,也很好理解,效果也相对不错。首先我们要尝试从文本中提取出关键词,也就是最能描述文章主题的关键词。

TF-IDF

  • 最直观的想法是统计词频(TF):统计每个词在文本中出现的次数,出现的越频繁,那么就越可能是这个文章的关键词。但这样还不够,因为有些实际无用的词出现的频率会很高,比如“的”、“是”、“在”这样的单词,我们称之为停用词,应该过滤掉。
  • 但即便过滤掉后,还要考虑剩下的词中,有的词会是很常见的词,有的词会是很少见的词。一般来说,如果很少见的词在文本中出现的次数很多,那么它比起常见的词,成为文本关键词的可能性要更大。
  • 引入逆文档频率(IDF)的概念:可以理解IDF是每一个词重要性的权重,一个词越少见,它的权重就越大(因为更有可能符合主题),反之,一个词越常见,它的IDF就越小。
  • 于是,我们可以使用TF*IDF这个乘积来描述某个词对文章的“重要性”。

欧式距离

  • 就是计算欧式几何坐标系中两个点的距离(当然也需要向量化),距离越大说明相似度越低.
    汉明距离
  • 这个在计算图片相似度的时候会用到,汉明距离只是简单的计算两个序列中,有多少位是不一样的,一般用于哈希的对比。
    编辑距离
  • 又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

项目感受

  • 首先最大的收获就是这个项目使我把C++的STL正正经经的用了一遍。让我对那些容器有了一定的理解。
  • 这个项目是偏向于算法的,在实现过程中更注重自己对于多种情况的不同处理,以及分析不同情况可能会出现什么不同的结果。一些条件的判断啊,还有对于C++语法的掌握情况之类的东西。
  • 当然少不了使用 jieba 时,对于 VS 环境的配置。途中我也经历了VS下的debug 模式和 release 模式的不同。
  • 算法呢,一定要注意其严谨性,如果实在不能实现理想的功能,但是要再合适的场景之下构造出合适的算法。让条件成为可能。
最后附上UTF-8和GBK两种编码之间的转换函数
string gbk_utf8(string str)    //GBK转换为UTF-8
{
	//获取buffer大小
	int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len];
	//GBK-->UTF16
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* utf8char = new char[len];
	//utf16-->utf8
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8char, len, NULL, NULL);
	string out(utf8char);

	if (wstr != NULL)
	{
		delete[] wstr;
		wstr = NULL;
	}
	if (utf8char != NULL)
	{
		delete[] utf8char;
		utf8char = NULL;
	}
	return out;
}

string utf8_gbk(string str)   //UTF-8转换为GBK
{
	//获取buffer大小
	int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len];
	//utf8-->utf16
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wstr, len);

	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* gbkchar = new char[len];
	//utf16--->gbk
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, gbkchar, len, NULL, NULL);

	string out(gbkchar);

	if (wstr != NULL)
	{
		delete[] wstr;
		wstr = NULL;
	}

	if (gbkchar != NULL)
	{
		delete[] gbkchar;
		gbkchar = NULL;
	}

	return out;
}

猜你喜欢

转载自blog.csdn.net/qq_40421919/article/details/88023524