Overview1. jieba分词工具2. Word2Vec2.1 Spark Word2Vec2.2 NLP ChineseEmbedding3. Top N相似近邻搜索3.1 scipy余弦相似度3.2 LSH局部敏感哈希 Overview 内容相似推荐算法，是推荐系统当中的一个常用的算法。假设我们做的是文章推荐，那么，我们该怎样求两篇文章的相似度呢？本文将记录几个常用工具的使用方法。 1. jieba分词工具 可以说是当前最好用的中文分词组件。我们拿到文章的标题、摘要、全文之后，可以用jieba提取关键词，然后去另一篇文章当中做Doc2Vec，把另一篇文章转化为一个向量，可以用平均或者加权平均的方式得到一个文章的向量。 首先安装这个组件： pip3 install jieba 之后就可以直接导入使用了： import jieba seg_list = jieba.cut("我正在做推荐系统当中的内容相似推荐部分。", cut_all=False) print("Default Mode: " + "/ ".join(seg_list)) # 精确模式 输出如下： Default Mode: 我/ 正在/ 做/ 推荐/ 系统/ 当中/ 的/ 内容/ 相似/ 推荐/ 部分/ 。 直接分词会把所有的词都得到，这样显然是不符合要求的。我们可以提取关键词功能来获得最重要的K个关键词。 import jieba.analyse key_words = jieba.analyse.extract_tags("我正在做推荐系统当中的内容相似推荐部分。", topK=3, withWeight=True, allowPOS=()) print(key_words) 显示如下： [('推荐', 1.386500847515), ('当中', 0.82161213919375), ('相似', 0.80830253373)] 我们会得到一个带权重的关键词列表。 这种只能对文章进行精确匹配，鲁棒性稍微差点。因此我们更需要下面这种更强大的工具Word2Vec。 2. Word2Vec Word2Vec其实是一个神经网络模型。我们不用自己实现，可以使用开源届的现有工具，Spark Word2Vec或腾讯Word2Vec工具NLP ChineseEmbedding。 2.1 Spark Word2Vec 具体用法如下： from pyspark.sql import SparkSession from pyspark.sql import functions as F from pyspark.ml.feature import Word2Vec spark = SparkSession.builder.appName("Spark Word2Vec") \ .master("spark://***.***.***.***:7077") \ .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))) 最后我们得到如下答案： 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。我们这里只记录它是怎么用的。 首先，我们下载到本地，然后解压缩： 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模型。 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这个包里，这个包对于做机器学习的人来说已经很熟悉了，不再赘述。 from scipy.spatial import distance distance.cosine([1, 0, 0], [0, 1, 0]) 这个方式会有问题，每两个物品都对比余弦相似度，那么时间复杂度为$O(N^{2})$，这在推荐系统中是不允许的. 3.2 LSH局部敏感哈希 Locality Sensitive Hashing我们可以从Spark文档当中找到介绍 Locality Sensitive Hashing。 原理是将备选物品哈希到M个分桶当中，然后计算每个分桶里面物品的相似物品。这样性能就提升了很多。 这样，从算法原理上就完成了内容相似推荐。