Overview
内容相似推荐算法,是推荐系统当中的一个常用的算法。假设我们做的是文章推荐,那么,我们该怎样求两篇文章的相似度呢?本文将记录几个常用工具的使用方法。
1. jieba
分词工具
可以说是当前最好用的中文分词组件。我们拿到文章的标题、摘要、全文之后,可以用jieba
提取关键词,然后去另一篇文章当中做Doc2Vec
,把另一篇文章转化为一个向量,可以用平均或者加权平均的方式得到一个文章的向量。
首先安装这个组件:
1 | pip3 install jieba |
之后就可以直接导入使用了:
1 2 3 | import jieba seg_list = jieba.cut( "我正在做推荐系统当中的内容相似推荐部分。" , cut_all = False ) print ( "Default Mode: " + "/ " .join(seg_list)) # 精确模式 |
输出如下:
1 | Default Mode: 我/ 正在/ 做/ 推荐/ 系统/ 当中/ 的/ 内容/ 相似/ 推荐/ 部分/ 。 |
直接分词会把所有的词都得到,这样显然是不符合要求的。我们可以提取关键词功能来获得最重要的K
个关键词。
1 2 3 | import jieba.analyse key_words = jieba.analyse.extract_tags( "我正在做推荐系统当中的内容相似推荐部分。" , topK = 3 , withWeight = True , allowPOS = ()) print (key_words) |
显示如下:
1 | [( '推荐' , 1.386500847515 ), ( '当中' , 0.82161213919375 ), ( '相似' , 0.80830253373 )] |
我们会得到一个带权重的关键词列表。
这种只能对文章进行精确匹配,鲁棒性稍微差点。因此我们更需要下面这种更强大的工具Word2Vec
。
2. Word2Vec
Word2Vec
其实是一个神经网络模型。我们不用自己实现,可以使用开源届的现有工具,Spark Word2Vec
或腾讯Word2Vec
工具NLP ChineseEmbedding
。
2.1 Spark Word2Vec
具体用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | from pyspark.sql import SparkSession from pyspark.sql import functions as F from pyspark.ml.feature import Word2Vec spark = SparkSession.builder.appName( "Spark Word2Vec" ) \ .config( "spark.cores.max" , "10" ) \ .config( "spark.driver.memory" , "2G" ) \ .config( "spark.executor.memory" , "2G" ) \ .config( "spark.executor.cores" , "2" )\ .getOrCreate() # 输入数据可以是一个词袋、一个句子或者一个文档 documentDF = spark.createDataFrame([ ( "我 正在 做 推荐 系统 当中 的 内容 相似 推荐 部分" .split( " " ), ), ( "我 喜欢 做 推荐 系统" .split( " " ), ), ( "做 机器 学习 我 是 专业 的" .split( " " ), ) ], [ "text" ]) # 学习一个词到向量的映射模型 word2Vec = Word2Vec(vectorSize = 3 , minCount = 0 , inputCol = "text" , outputCol = "result" ) model = word2Vec.fit(documentDF) result = model.transform(documentDF) for row in result.collect(): text, vector = row print ( "Text: [%s] => \nVector: %s\n" % ( ", " .join(text), str (vector))) |
最后我们得到如下答案:
1 2 3 4 5 6 7 8 | Text: [我, 正在, 做, 推荐, 系统, 当中, 的, 内容, 相似, 推荐, 部分] => Vector: [0.02447097257456996,-0.05411485582590103,0.02040436087091538] Text: [我, 喜欢, 做, 推荐, 系统] => Vector: [0.04216975644230843,-0.0064331904053688055,-0.011528981802985073] Text: [做, 机器, 学习, 我, 是, 专业, 的] => Vector: [0.019645389967731065,0.010864340301070894,-0.0007330668491444417] |
更多内容可以参考Spark
官方文档Extracting, transforming and selecting features。
这个虽然强大,但是受制于我们手头的语料,即训练数据不够充分,所以我们不建议自己训练一个Word2Vec
模型,我们更推荐用更强大的腾讯Word2Vec
——NLP ChineseEmbedding
。
2.2 NLP ChineseEmbedding
这个工具非常有名,具体介绍可以看官网Tencent AI Lab Embedding Corpus for Chinese Words and Phrases。我们这里只记录它是怎么用的。
首先,我们下载到本地,然后解压缩:
1 2 3 | wget https: //ai .tencent.com /ailab/nlp/zh/data/Tencent_AILab_ChineseEmbedding . tar .gz tar -zxvf Tencent_AILab_ChineseEmbedding. tar .gz |
得到Tencent_AILab_ChineseEmbedding.txt
这个文件。
然后我们需要安装gensim
包来辅助我们使用腾讯的word2vec
模型。
1 2 3 4 | pip3 install gensim from gensim.models import KeyedVectors wv_from_text = KeyedVectors.load_word2vec_format( 'Tencent_AILab_ChineseEmbedding.txt' , binary=False) model=wv_from_text.wv |
这样,我们就得到了这个Word2Vec
模型。
可以通过model.word_vec
方法将文字转成向量。
3. Top N
相似近邻搜索
在我们将文字转成向量之后,可以比较两个向量的相似度,进而选取最相似的N
个向量。而相似近邻搜索主要有两种方式:scipy余弦相似度
和LSH局部敏感哈希
。
3.1 scipy余弦相似度
scipy.spatial.distance.cosine
这个方法在scipy
这个包里,这个包对于做机器学习的人来说已经很熟悉了,不再赘述。
1 2 | from scipy.spatial import distance distance.cosine([ 1 , 0 , 0 ], [ 0 , 1 , 0 ]) |
这个方式会有问题,每两个物品都对比余弦相似度,那么时间复杂度为O(N2),这在推荐系统中是不允许的.
3.2 LSH局部敏感哈希
Locality Sensitive Hashing
我们可以从Spark
文档当中找到介绍 Locality Sensitive Hashing。
原理是将备选物品哈希到M
个分桶当中,然后计算每个分桶里面物品的相似物品。这样性能就提升了很多。
这样,从算法原理上就完成了内容相似推荐。