开发环境
系统: macOS Sierra; 开发软件: PyChram CE; 运行环境: Python3.6
需求分析
在用户阅读某篇文章的时候,为用户推荐更多与在读文章内容相似的文章
概念
<b>相似推荐</b>:当用户表现出对某人或某物感兴趣时,为他/她推荐相似的人或物,核心思想:人以类聚,物以群分;
<b>协同过滤推荐</b>:指利用用户过去的行为或意见,预测当前用户最喜欢哪些东西或对哪些东西感兴趣
采用余弦相似度原理来实现相似文章推荐
<b>原理:</b>
将每篇文章的词频统计结果当作一个向量,如果两篇文章向量的夹角越小即余弦值越接近1,那么我们说这两篇文章越相似
假如有如下两篇文章
文章A - '放假我喜欢弹吉他,看书'
文章B - '放假我不喜欢看书,喜欢打球'
这两篇文章的词频统计结果如下:
放假 我 喜欢 弹 吉他 看书 不 打球
文章A 1 1 1 1 1 1 0 0
文章B 1 1 2 0 0 1 1 1
则根据余弦计算公式,文章A和文章B两个向量间的余弦值计算如下:
若余弦值越接近1, 则说明文章A和B越相似
-
导入需要用到的包
import os
import codecs
import re
import jieba
import pandas
import numpy
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import pairwise_distances
-
创建语料库
# 创建语料库
filePaths = []
fileContents = []
for root, dirs, files in os.walk(
'data/SogouC.mini/Sample'
):
for name in files:
filePath = os.path.join(root, name)
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
filePaths.append(filePath)
fileContents.append(fileContent)
corpus = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
})
语料库中的文章是从搜狗实验室下载的,内容如下:
创建的语料库如下:
-
对文章进行分词
# 匹配中文分词
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
# 对每篇文章进行分词处理
for index, row in corpus.iterrows():
fileContent = row['fileContent']
segments = []
segs = jieba.cut(fileContent) # 分词默认以','分隔
for seg in segs:
if zhPattern.search(seg):
segments.append(seg)
row['fileContent'] = ' '.join(segments) # 将分词以空格分隔
分词后结果如下:
-
统计词频,将词频向量化
# 读取停用词文件
stopWords = pandas.read_csv(
'data/StopwordsCN.txt',
encoding='utf-8',
index_col=False,
quoting=3,
sep='\t'
)
# 词频统计 & 文档向量化
countVectorizer = CountVectorizer(
stop_words=list(stopWords['stopword'].values),
min_df=0,
token_pattern=r"\b\w+\b"
)
textVector = countVectorizer.fit_transform(corpus['fileContent'])
词频矩阵如下:
-
统计词频矩阵的余弦相似度计算
# 统计词频矩阵的余弦相似度计算
distance_matrix = pairwise_distances(
textVector,
metric='cosine'
)
运行结果如下:
上面的矩阵代表的意思是两个文章(即两个向量)之间的夹角值,这里我用x代替上面矩阵中的数值。 为什么斜对角的数值都为0呢?因为文章跟本身是完全相同的,所以两个向量相同,夹角值为0
文章1 文章2 文章3 ... 文章n
文章1 0 x x ... x
文章2 x 0 x ... x
文章3 x x 0 ... x
... ... ... ... ... ...
文章n x x x ... 0
-
获取与该文章最相似的3篇文章(即矩阵中值最小的前三个)
# 获取与本篇文章相似度最高的三篇文章
sort_matrix = numpy.argsort(distance_matrix, axis=1)[:, 1:4] # argsort为升序排列,取第1列到第3列的值,第0列为自己本身
similarity = pandas.Index(filePaths)[sort_matrix].values
similarityDF = pandas.DataFrame({
'filePath': filePaths,
's1': similarity[:, 0],
's2': similarity[:, 1],
's3': similarity[:, 2],
})
最后结果如下:
-
参考
小蚊子数据分析