众所周知,个性化推荐系统能够根据用户的兴趣、偏好等信息向用户推荐相关内容,使得用户更感兴趣,从而提升用户体验,提高用户粘度,之前我们曾经使用协同过滤算法构建过个性化推荐系统,但基于显式反馈的算法就会有一定的局限性,本次我们使用无监督的Lda文本聚类方式来构建文本的个性化推荐系统。

推荐算法:协同过滤/Lda聚类

我们知道,协同过滤算法是一种基于用户的历史行为来推荐物品的算法。协同过滤算法利用用户之间的相似性来推荐物品,如果两个用户对某些物品的评分相似,则协同过滤算法会将这两个用户视为相似的,并向其中一个用户推荐另一个用户喜欢的物品。

说白了,它基于用户的显式反馈,什么是显式反馈?举个例子,本如本篇文章,用户看了之后,可能会点赞,也可能会疯狂点踩,或者写一些关于文本的评论,当然评论内容可能是负面、正面或者中性,所有这些用户给出的行为,都是显式反馈,但如果用户没有反馈出这些行为,就只是看了看,协同过滤算法的效果就会变差。

LDA聚类是一种文本聚类算法,它通过对文本进行主题建模来聚类文本。LDA聚类算法在聚类文本时,不考虑用户的历史行为,而是根据文本的内容和主题来聚类。

说得通俗一点,协同过滤是一种主动推荐,系统根据用户历史行为来进行内容推荐,而LDA聚类则是一种被动推荐,在用户还没有产生用户行为时,就已经开始推荐动作。

LDA聚类的主要目的是将文本分为几类,使得每类文本的主题尽可能相似。

LDA聚类算法的工作流程大致如下:

1.对文本进行预处理,去除停用词等。

2.使用LDA模型对文本进行主题建模,得到文本的主题分布。

3.将文本按照主题分布相似性进行聚类。

4.将聚类结果作为类标签,对文本进行分类。

大体上,LDA聚类算法是一种自动将文本分类的算法,它通过对文本进行主题建模,将文本按照主题相似性进行聚类,最终实现文本的分类。

Python3.10实现

实际应用层面,我们需要做的是让主题模型能够识别在文本里的主题,并且挖掘文本信息中隐式信息,并且在主题聚合、从非结构化文本中提取信息。

首先安装分词以及聚类模型库:

pip3 install jieba
pip3 install gensim

随后进行分词操作,这里以笔者的几篇文章为例子:

import jieba
import pandas as pd
import numpy as np
title1="乾坤大挪移,如何将同步阻塞(sync)三方库包转换为异步非阻塞(async)模式?Python3.10实现。"
title2="Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现"
title3="周而复始,往复循环,递归、尾递归算法与无限极层级结构的探究和使用(Golang1.18)"
title4="彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-JWT和中间件(Middleware)的使用EP07"
content = [title1,title2, title3,title4] #分词
content_S = []
all_words = []
for line in content:
current_segment = [w for w in jieba.cut(line) if len(w)>1]
for x in current_segment:
all_words.append(x)
if len(current_segment) > 1 and current_segment != '\r\t':
content_S.append(current_segment)
#分词结果转为DataFrame
df_content = pd.DataFrame({'content_S':content_S}) print(all_words)

可以看到,这里通过四篇文章标题构建分词列表,最后打印分词结果:

['乾坤', '挪移', '如何', '同步', '阻塞', 'sync', '三方', '库包', '转换', '异步', '阻塞', 'async', '模式', 'Python3.10', '实现', 'Generator', '生成器', '入门', '初基', 'Coroutine', '原生', '协程', '登峰造极', 'Python3.10', '并发', '异步', '编程', 'async', '底层', '实现', '周而复始', '往复', '循环', '递归', '递归', '算法', '无限极', '层级', '结构', '探究', '使用', 'Golang1.18', '彩虹', '女神', '长空', 'Go', '语言', '进阶', 'Go', '语言', '高性能', 'Web', '框架', 'Iris', '项目', '实战', 'JWT', '中间件', 'Middleware', '使用', 'EP07']

接着就可以针对这些词进行聚类操作,我们可以先让ChatGPT帮我们进行聚类看看结果:

可以看到,ChatGPT已经帮我们将分词结果进行聚类操作,分为两大类:Python和Golang。

严谨起见,我们可以针对分词结果进行过滤操作,过滤内容是停用词,停用词是在文本分析、自然语言处理等应用中,用来过滤掉不需要的词的。通常来说,停用词是指在英文中的介词、代词、连接词等常用词,在中文中的助词、介词、连词等常用词:

———
》),
)÷(1-
”,
)、
=(
:


&
*
一一
~~~~

.

.一
./
--

=″

[*]
}>
[⑤]]
[①D]
c]
ng昉

//


[②e]
[②g]
={
}
,也


[①⑥]
[②B]
[①a]
[④a]
[①③]
[③h]
③]
1.
--
[②b]
’‘
×××
[①⑧]
0:2
=[
[⑤b]
[②c]
[④b]
[②③]
[③a]
[④c]
[①⑤]
[①⑦]
[①g]
∈[
[①⑨]
[①④]
[①c]
[②f]
[②⑧]
[②①]
[①C]
[③c]
[③g]
[②⑤]
[②②]
一.
[①h]
.数
[]
[①B]
数/
[①i]
[③e]
[①①]
[④d]
[④e]
[③b]
[⑤a]
[①A]
[②⑧]
[②⑦]
[①d]
[②j]
〕〔
][
://
′∈
[②④
[⑤e]
12%
b]
...
...................
…………………………………………………③
ZXFITL
[③F]

[①o]
]∧′=[
∪φ∈
′|
{-
②c

[③①]
R.L.
[①E]
Ψ
-[*]-

.日
[②d]
[②
[②⑦]
[②②]
[③e]
[①i]
[①B]
[①h]
[①d]
[①g]
[①②]
[②a]
f]
[⑩]
a]
[①e]
[②h]
[②⑥]
[③d]
[②⑩]
e]


元/吨
[②⑩]
2.3%
5:0
[①]
::
[②]
[③]
[④]
[⑤]
[⑥]
[⑦]
[⑧]
[⑨]
……
——
?












,

'
?
·
———
──
?

<
>




[
]
(
)
-
+

×

/











В
"
;
#
@
γ
μ
φ
φ.
×
Δ


sub
exp
sup
sub
Lex





+ξ
++

-β

<±
<Δ
<λ
<φ
<<
=

=☆
=-

>λ
_
~±
~+
[⑤f]
[⑤d]
[②i]

[②G]
[①f]
LI

[-
......

[③⑩]
第二
一番
一直
一个
一些
许多

有的是
也就是说
末##末



哎呀
哎哟


俺们

按照

吧哒

罢了


本着

比方
比如
鄙人

彼此


别的
别说

并且
不比
不成
不单
不但
不独
不管
不光
不过
不仅
不拘
不论
不怕
不然
不如
不特
不惟
不问
不只

朝着

趁着



除此之外
除非
除了

此间
此外

从而



但是

当着



的话

等等


叮咚

对于

多少

而况
而且
而是
而外
而言
而已
尔后
反过来
反过来说
反之
非但
非徒
否则

嘎登




各个
各位
各种
各自

根据


故此
固然
关于


果然
果真


哈哈



何处
何况
何时


哼唷
呼哧


还是
还有
换句话说
换言之

或是
或者
极了

及其
及至

即便
即或
即令
即若
即使

几时


既然
既是
继而
加之
假如
假若
假使
鉴于


较之

接着
结果

紧接着
进而

尽管

经过

就是
就是说

具体地说
具体说来
开始
开外



可见
可是
可以
况且


来着

例如


连同
两者



另外
另一方面



慢说
漫说



每当

莫若

某个
某些


哪边
哪儿
哪个
哪里
哪年
哪怕
哪天
哪些
哪样

那边
那儿
那个
那会儿
那里
那么
那么些
那么样
那时
那些
那样

乃至



你们


宁可
宁肯
宁愿


啪达
旁人


凭借

其次
其二
其他
其它
其一
其余
其中

起见
起见
岂但
恰恰相反
前后
前者

然而
然后
然则

人家

任何
任凭

如此
如果
如何
如其
如若
如上所述

若非
若是

上下
尚且
设若
设使
甚而
甚么
甚至
省得
时候
什么
什么样
使得

是的
首先

谁知

顺着
似的

虽然
虽说
虽则

随着

所以

他们
他人

它们

她们

倘或
倘然
倘若
倘使


通过

同时

万一



为何
为了
为什么
为着

嗡嗡

我们

呜呼
乌乎
无论
无宁
毋宁


相对而言


向着



沿
沿着

要不
要不然
要不是
要么
要是

也罢
也好

一般
一旦
一方面
一来
一切
一样
一则

依照


以便
以及
以免
以至
以至于
以致
抑或

因此
因而
因为



由此可见
由于

有的
有关
有些


于是
于是乎

与此同时
与否
与其
越是
云云

再说
再者

在下

咱们


怎么
怎么办
怎么样
怎样


照着


这边
这儿
这个
这会儿
这就是说
这里
这么
这么点儿
这么些
这么样
这时
这些
这样
正如


之类
之所以
之一
只是
只限
只要
只有

至于
诸位

着呢

自从
自个儿
自各儿
自己
自家
自身
综上所述
总的来看
总的来说
总的说来
总而言之
总之

纵令
纵然
纵使
遵照
作为







喔唷



这里使用哈工大的停用词列表。

首先加载停用词列表,然后进行过滤操作:

#去除停用词
def drop_stopwords(contents,stopwords):
contents_clean = []
all_words = []
for line in contents:
line_clean = []
for word in line:
if word in stopwords:
continue
line_clean.append(word)
all_words.append(word)
contents_clean.append(line_clean)
return contents_clean,all_words #停用词加载
stopwords = pd.read_table('stop_words.txt',names = ['stopword'],quoting = 3)
contents = df_content.content_S.values.tolist() contents_clean,all_words = drop_stopwords(contents,stopwords)

接着交给Gensim进行聚类操作:



from gensim import corpora,models,similarities
import gensim dictionary = corpora.Dictionary(contents_clean)
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]
lda = gensim.models.ldamodel.LdaModel(corpus=corpus,id2word=dictionary,num_topics=2,random_state=3) #print(lda.print_topics(num_topics=2, num_words=4)) for e, values in enumerate(lda.inference(corpus)[0]):
print(content[e])
for ee, value in enumerate(values):
print('\t分类%d推断值%.2f' % (ee, value))

这里使用LdaModel模型进行训练,分类设置(num_topics)为2种,随机种子(random_state)为3,在训练机器学习模型时,很多模型的训练过程都会涉及到随机数的生成,例如随机梯度下降法(SGD)就是一种随机梯度下降的优化算法。在训练过程中,如果不设置random_state参数,则每次训练结果可能都不同。而设置random_state参数后,每次训练结果都会相同,这就方便了我们在调参时对比模型的效果。如果想要让每次训练的结果都随机,可以将random_state参数设置为None。

程序返回:

[['乾坤', '挪移', '同步', '阻塞', 'sync', '三方', '库包', '转换', '异步', '阻塞', 'async', '模式', 'Python3.10', '实现'], ['Generator', '生成器', '入门', '初基', 'Coroutine', '原生', '协程', '登峰造极', 'Python3.10', '并发', '异步', '编程', 'async', '底层', '实现'], ['周而复始', '往复', '循环', '递归', '递归', '算法', '无限极', '层级', '结构', '探究', '使用', 'Golang1.18'], ['彩虹', '女神', '长空', 'Go', '语言', '进阶', 'Go', '语言', '高性能', 'Web', '框架', 'Iris', '项目', '实战', 'JWT', '中间件', 'Middleware', '使用', 'EP07']]
乾坤大挪移,如何将同步阻塞(sync)三方库包转换为异步非阻塞(async)模式?Python3.10实现。
分类0推断值0.57
分类1推断值14.43
Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现
分类0推断值0.58
分类1推断值15.42
周而复始,往复循环,递归、尾递归算法与无限极层级结构的探究和使用(Golang1.18)
分类0推断值12.38
分类1推断值0.62
彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-JWT和中间件(Middleware)的使用EP07
分类0推断值19.19
分类1推断值0.81

可以看到,结果和ChatGPT聚类结果一致,前两篇为一种分类,后两篇为另外一种分类。

随后可以将聚类结果保存为模型文件:

lda.save('mymodel.model')

以后有新的文章发布,直接对新的文章进行分类推测即可:

from gensim.models import  ldamodel
import pandas as pd
import jieba
from gensim import corpora doc0="巧如范金,精比琢玉,一分钟高效打造精美详实的Go语言技术简历(Golang1.18)"
# 加载模型
lda = ldamodel.LdaModel.load('mymodel.model') content = [doc0] #分词
content_S = []
for line in content:
current_segment = [w for w in jieba.cut(line) if len(w)>1]
if len(current_segment) > 1 and current_segment != '\r\t':
content_S.append(current_segment)
#分词结果转为DataFrame
df_content = pd.DataFrame({'content_S':content_S}) #去除停用词
def drop_stopwords(contents,stopwords):
contents_clean = []
all_words = []
for line in contents:
line_clean = []
for word in line:
if word in stopwords:
continue
line_clean.append(word)
all_words.append(word)
contents_clean.append(line_clean)
return contents_clean,all_words #停用词加载
stopwords = pd.read_table('stop_words.txt',names = ['stopword'],quoting = 3)
contents = df_content.content_S.values.tolist() contents_clean,all_words = drop_stopwords(contents,stopwords) dictionary = corpora.Dictionary(contents_clean) word = [w for w in jieba.cut(doc0)] bow = dictionary.doc2bow(word)
print(lda.get_document_topics(bow))

程序返回:

➜  nlp_chinese /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/nlp_chinese/new_text.py"
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/5x/gpftd0654bv7zvzyv39449rc0000gp/T/jieba.cache
Loading model cost 0.264 seconds.
Prefix dict has been built successfully.
[(0, 0.038379338), (1, 0.9616206)]

这里显示文章推断结果为分类2,也就是Golang类型的文章。

完整调用逻辑:

import jieba
import pandas as pd
import numpy as np
from gensim.models import ldamodel
from gensim import corpora,models,similarities
import gensim class LdaRec: def __init__(self,cotent:list) -> None: self.content = content
self.contents_clean = []
self.lda = None def test_text(self,content:str): self.lda = ldamodel.LdaModel.load('mymodel.model')
self.content = [content] #分词
content_S = []
for line in self.content:
current_segment = [w for w in jieba.cut(line) if len(w)>1]
if len(current_segment) > 1 and current_segment != '\r\t':
content_S.append(current_segment)
#分词结果转为DataFrame
df_content = pd.DataFrame({'content_S':content_S}) contents = df_content.content_S.values.tolist() dictionary = corpora.Dictionary(contents) word = [w for w in jieba.cut(content)] bow = dictionary.doc2bow(word)
print(self.lda.get_document_topics(bow)) # 训练
def train(self,num_topics=2,random_state=3): dictionary = corpora.Dictionary(self.contents_clean)
corpus = [dictionary.doc2bow(sentence) for sentence in self.contents_clean]
self.lda = gensim.models.ldamodel.LdaModel(corpus=corpus,id2word=dictionary,num_topics=num_topics,random_state=random_state) for e, values in enumerate(self.lda.inference(corpus)[0]):
print(self.content[e])
for ee, value in enumerate(values):
print('\t分类%d推断值%.2f' % (ee, value)) # 过滤停用词
def drop_stopwords(self,contents,stopwords):
contents_clean = []
for line in contents:
line_clean = []
for word in line:
if word in stopwords:
continue
line_clean.append(word)
contents_clean.append(line_clean)
return contents_clean def cut_word(self) -> list:
#分词
content_S = []
for line in self.content:
current_segment = [w for w in jieba.cut(line) if len(w)>1]
if len(current_segment) > 1 and current_segment != '\r\t':
content_S.append(current_segment) #分词结果转为DataFrame
df_content = pd.DataFrame({'content_S':content_S}) # 停用词列表
stopwords = pd.read_table('stop_words.txt',names = ['stopword'],quoting = 3) contents = df_content.content_S.values.tolist()
stopwords = stopwords.stopword.values.tolist() self.contents_clean = self.drop_stopwords(contents,stopwords) if __name__ == '__main__': title1="乾坤大挪移,如何将同步阻塞(sync)三方库包转换为异步非阻塞(async)模式?Python3.10实现。"
title2="Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现"
title3="周而复始,往复循环,递归、尾递归算法与无限极层级结构的探究和使用(Golang1.18)"
title4="彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-JWT和中间件(Middleware)的使用EP07"
content = [title1,title2, title3,title4] lr = LdaRec(content) lr.cut_word() lr.train() lr.lda.save('mymodel.model') lr.test_text("巧如范金,精比琢玉,一分钟高效打造精美详实的Go语言技术简历(Golang1.18)")

至此,基于聚类的推荐系统构建完毕,每一篇文章只需要通过既有分类模型进行训练,推断分类之后,给用户推送同一分类下的文章即可,截止本文发布,该分类模型已经在本站进行落地实践:

结语

金无足赤,LDA聚类算法也不是万能的,LDA聚类算法有许多超参数,包括主题个数、学习率、迭代次数等,这些参数的设置对结果有很大影响,但是很难确定最优参数,同时聚类算法的时间复杂度是O(n^2)级别的,在处理大规模文本数据时,计算速度较慢,反之,在样本数据较少的情况下,模型的泛化能力较差。最后,奉上项目地址,与君共觞:https://github.com/zcxey2911/Lda-Gensim-Recommended-System-Python310

物以类聚人以群分,通过GensimLda文本聚类构建人工智能个性化推荐系统(Python3.10)的更多相关文章

  1. 10.HanLP实现k均值--文本聚类

    笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 10. 文本聚类 正所谓物以类聚,人以群分.人们在获取数据时需要整理,将相似的数据 ...

  2. [python] 使用Jieba工具中文分词及文本聚类概念

    声明:由于担心CSDN博客丢失,在博客园简单对其进行备份,以后两个地方都会写文章的~感谢CSDN和博客园提供的平台.        前面讲述了很多关于Python爬取本体Ontology.消息盒Inf ...

  3. [转]python进行中文文本聚类(切词以及Kmeans聚类)

    简介 查看百度搜索中文文本聚类我失望的发现,网上竟然没有一个完整的关于Python实现的中文文本聚类(乃至搜索关键词python 中文文本聚类也是如此),网上大部分是关于文本聚类的Kmeans聚类的原 ...

  4. K-means算法及文本聚类实践

    K-Means是常用的聚类算法,与其他聚类算法相比,其时间复杂度低,聚类的效果也还不错,这里简单介绍一下k-means算法,下图是一个手写体数据集聚类的结果. 基本思想 k-means算法需要事先指定 ...

  5. 灵玖软件NLPIRParser智能文本聚类

    随着互联网的迅猛发展,信息的爆炸式增加,信息超载问题变的越来越严重,信息的更新率也越来越高,用户在信息海洋里查找信息就像大海捞针一样.搜索引擎服务应运而生,在一定程度上满足了用户查找信息的需要.然而互 ...

  6. pyhanlp 文本聚类详细介绍

    文本聚类 文本聚类简单点的来说就是将文本视作一个样本,在其上面进行聚类操作.但是与我们机器学习中常用的聚类操作不同之处在于. 我们的聚类对象不是直接的文本本身,而是文本提取出来的特征.因此如何提取特征 ...

  7. 文本挖掘之文本聚类(MapReduce)

    刘 勇  Email:lyssym@sina.com 简介 针对大数量的文本数据,采用单线程处理时,一方面消耗较长处理时间,另一方面对大量数据的I/O操作也会消耗较长处理时间,同时对内存空间的消耗也是 ...

  8. 文本挖掘之文本聚类(DBSCAN)

    刘 勇   Email:lyssym@sina.com 简介 鉴于基于划分的文本聚类方法只能识别球形的聚类,因此本文对基于密度的文本聚类算法展开研究.DBSCAN(Density-Based Spat ...

  9. python聚类算法实战详细笔记 (python3.6+(win10、Linux))

    python聚类算法实战详细笔记 (python3.6+(win10.Linux)) 一.基本概念:     1.计算TF-DIF TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库 ...

  10. 图像检索(2):均值聚类-构建BoF

    在图像检索时,通常首先提取图像的局部特征,这些局部特征通常有很高的维度(例如,sift是128维),有很多的冗余信息,直接利用局部特征进行检索,效率和准确度上都不是很好.这就需要重新对提取到的局部特征 ...

随机推荐

  1. uni-app 如何优雅的使用权限认证并对本地文件上下起手

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1.起因 最近有一个需求,需要使用自定义插件,来对接硬件功能,需要配合对手机的权限进行判断和提示,并在对接后对本地文件进行操作,这里给大家 ...

  2. day47-JDBC和连接池03

    JDBC和连接池03 8.事务 8.1事务介绍 基本介绍 JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而 ...

  3. 认识 Redis client-output-buffer-limit 参数与源码分析

    概述 Redis 的 client-output-buffer-limit 可以用来强制断开无法足够快从 redis 服务器端读取数据的客户端.保护机制规则如下: [hard limit] 大小限制, ...

  4. 频道插件如何对接圈子 齐博x1齐博x2齐博x3齐博x4齐博x5齐博x6齐博x7齐博x8齐博x9齐博x10

    圈子黄页里要显示对应频道的数据列表,一般没有特殊要求的话,不需要建立PHP文件, 只须要做好模板即可,比如 \template\index_style\default\qun\shop\index.h ...

  5. 小米MIUI禁止系统更新

    删除downloaded_rom的文件夹,随便找一个文件(文件,不是文件夹),重名为downloaded_rom(是把一个文件重命名),这样系统后台偷偷下载时,就不知道该存放更新包的文件,就无法偷偷更 ...

  6. Jquery对类的操作

    Jquery对类的基本操作 $("#Div_BillSon div").on('click', function (e) { $("#Div_BillSon") ...

  7. Pandas常用方法

    数据处理很多需要用到pandas,有两个基本类型:Series表示一维数据,DataFrame表示多维.以下是一些常用方法的整理: pandas.Series 创建 Series pandas.Ser ...

  8. 使用VsCode调试UE5的PuerTs

    使用VsCode调试UE5的PuerTs 1.下载测试的Demo项目 配置PuerTs的步骤这里不赘述. 2.准备工作 2.1 打开项目 正常来说,直接打开项目可以看到如下画面 如果直接点击运行,可以 ...

  9. Pyhton基础部分:6、与用户交互、基础运算符

    目录 一.python数据类型 1.布尔值bool 2.元组tuple 3.集合set 二.与用户交互 1.获取用户输入 2.输出内部信息 3.语言环境差异 三.格式化输入 1.代码实现 2.注意事项 ...

  10. 「浙江理工大学ACM入队200题系列」问题 L: 零基础学C/C++52——计算数列和2/1,3/2,5/3,8/5......

    本题是浙江理工大学ACM入队200题第五套中的L题 我们先来看一下这题的题面. 题面 题目描述 有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13,-- 计算这个数列的前n项和.注意: ...