8.7 案例:基于潜在狄利克雷分配(LDA)的内容主题挖掘
8.7.1 案例背景
本案例是从一堆新闻文件中建立相应的主题模型,然后得到不同模型的主题特点,并通过对新文本数据集的预测得到其可能的主题分类。
案例数据源文件有两部分,第一部分在“附件-chapter8”中的news_data.tar.gz压缩包中,该压缩包包含10个文件,这些是用来做主题模型的训练集;另外一个文件在相同目录下,名为article.txt,用来做主题预测。案例的程序文件chapter8_code1.py也在相同数据源目录之下。
本案例程序的默认工作目录为“附件-chapter8”(如果不是,请cd切换到该目录下,否则会报“IOError:File article.txt does not exist”)。
8.7.2 案例主要应用技术
本案例用到的主要技术包括:
数据预处理:中文分词、TF-IDF向量空间模型转换、字符串全角转半角、XML文件内容解析。
数据建模:潜在狄利克雷分配(LDA)模型。
主要用到的库包括:sys、tarfile、os、jieba、gensim、bs4,其中gensim是核心。
本案例的重点技术有3个:
使用bs4的BeautifulSoup做XML文件内容解析。
使用结巴分词工具做中文分词。
使用gensim中的LDA(潜在狄利克雷分配模型)做主题模型,并可以基于训练好的模型做新文本的主题预测。
8.7.3 案例数据
案例数据来自搜狐新闻2012年6月到7月的部分新闻数据,涵盖了新闻、家居、体育等主题频道。压缩包中有10个新闻文件,每个文件中包含多条新闻,每条新闻的格式相同,包含新闻URL、页面ID、页面标题和页面内容4部分。以下是文件内容格式示例:
<doc> <url>页面URL</url> <docno>页面ID</docno> <contenttitle>页面标题</contenttitle> <content>页面内容</content> </doc>
8.7.4 案例过程
步骤1 导入库。
import sys reload(sys) sys.setdefaultencoding('utf-8') import tarfile # tar压缩包库 import os # 操作系统功能模块 import jieba.posseg as pseg # 带词性标注的分词模块 from gensim import corpora, models # gensim的词频统计和主题建模模块 from bs4 import BeautifulSoup # 用于XML格式化处理
本案例主要用到了以下库:
sys:系统库,用来将默认编码设置为UTF-8,目的是更好的处理中文。
tarfile:用来解析原始数据压缩文件。
os:用来判断数据是否存在以及遍历目录文件。
jieba:中文分词,这里使用的是带词性标注的分析模块。
gensim:主题模型库,这里使用的是其中的词频统计和主题建模模块。
bs4:这里用到了其中的BeautifulSoup做XML文件内容解析。
步骤2 定义功能函数,包括中文分词、文本预处理、全角转半角、解析文件内容。
中文分词:
def jieba_cut(text): ''' 将输入的文本句子根据词性标注做分词 :param text: 文本句子,字符串型 :return: 符合规则的分词结果 ''' rule_words = ['z', 'vn', 'v', 't', 'nz', 'nr', 'ns', 'n', 'l', 'i', 'j', 'an', 'a'] # 只保留状态词、名动词、动词、时间词、其他名词、人名、地名、名词、习用语、简称略语、成语、形容词、名形词 words = pseg.cut(text) # 分词 seg_list = [] # 列表用于存储每个文件的分词结果 for word in words: # 循环得到每个分词 if word.flag in rule_words: seg_list.append(word.word) # 将分词追加到列表 return seg_list
该函数主要用于将输入的文本句子根据词性标注做过滤,只保留符合条件的分词结果,由于分词过程中加入了词类判别,因此该过程用时较长。其输入参数如下:
text:文本句子,字符串型。
函数返回:符合规则的分词结果。
该函数的具体定义如下:
首先定义了一个要保留词的类别列表rule_words,只保留状态词、名动词、动词、时间词、其他名词、人名、地名、名词、习用语、简称略语、成语、形容词、名形词。完整分词类别,请见第4章表4-8常用结巴分词词性分类。
使用jieba.posseg做分词得到一个迭代对象words。
创建一个列表seg_list用于存储每个文件的分词结果。
在for循环中,通过word.flag属性判断类别是否属于保留词类别,如果属于则将word.word分词结果追加到结果列表中,最后得到的是一个嵌套列表,列表中的每个元素都是对应文件的分词组成的列表。
最后返回分词列表。
文本预处理:
def text_pro(words_list, tfidf_object=None, training=True): ''' gensim主题建模预处理过程,包含分词类别转字典、生成语料库和TF-IDF转换 :param words_list: 分词列表,列表型 :param tfidf_object: TF-IDF模型对象,该对象在训练阶段生成 :param training: 是否训练阶段,用来针对训练和预测两个阶段做预处理 :return: 如果是训练阶段,返回词典、TF-IDF对象和TF-IDF向量空间数据;如果是预测阶段,返回TF-IDF向量空间数据 ''' # 分词列表转字典 dic = corpora.Dictionary(words_list) # 将分词列表转换为字典形式 print ('{:*^60}'.format('token & word mapping review:')) for i, w in dic.items()[:5]: # 循环读出字典前5条的每个key和value,对应的是索引值和分词 print ('token:%s -- word:%s' % (i, w)) # 生成语料库 corpus = [] # 建立一个用于存储语料库的列表 for words in words_list: # 读取每个分词列表 corpus.append(dic.doc2bow(words)) # 将每个分词列表转换为语料库词袋(bag of words)形式的列表 print ('{:*^60}'.format('bag of words review:')) print (corpus[0]) # 打印输出第一条语料库 # TF-IDF转换 if training == True: tfidf = models.TfidfModel(corpus) # 建立TF-IDF模型对象 corpus_tfidf = tfidf[corpus] # 得到TF-IDF向量稀疏矩阵 print ('{:*^60}'.format('TF-IDF model review:')) for doc in corpus_tfidf: # 循环读出每个向量 print doc # 打印第一条向量 break # 跳出循环 return dic, corpus_tfidf, tfidf else: return tfidf_object[corpus]
该函数是gensim主题建模预处理过程,包含分词类别转字典、生成语料库和TF-IDF转换。由于在训练主题以及应用新的文本集做主题预测时都会用到该部分,因此单独拿出来用一个函数封装调用。其输入参数如下:
words_list:分词列表,列表型。
tfidf_object:TF-IDF模型对象,该对象在训练阶段生成。
training:是否训练阶段,用来针对训练和预测两个阶段分别做预处理。
函数返回:如果是训练阶段,返回词典、TF-IDF对象和TF-IDF向量空间数据;如果是预测阶段,返回TF-IDF向量空间数据。
该函数的具体定义如下:
分词列表转字典。使用corpora.Dictionary方法将列表转换为字典形式,转换后的字典是每个分词和对应的token列表。通过for循环,打印输出字典数据的前5条数据。
生成语料库。先建立一个用于存储语料库的空列表corpus,然后用for循环读取分词列表中的每个元素,使用字典对象的dic.doc2bow方法将每个分词列表转换为语料库词袋形式的列表,最后将转换后的元素追加到语料库列表中。语料库词袋的每个元素都是由token(分词对应的ID)和token计数组成,用于记录每个分词出现的次数。
TF-IDF转换。该功能需要根据training=True或training=False来区分训练集或预测集的调用,原因是在训练集中建立的TF-IDF模型在预测应用时不必重新建立,只需直接调用即可,因此可以通过if条件做判断。当训练集调用时(training=True),先使用model.TfidfModel建立TF-IDF模型对象tfidf,使用tfidf[corpus]转换为TF-IDF向量稀疏矩阵,然后打印该向量矩阵的第一条数据,使用break方法终止循环。最后返回的dic和corpus_tfidf在主题建模时使用、tfidf在预测新的文本数据集时使用。当预测集调用时,直接调用上述训练集的TF-IDF模型对象,应用到新的数据集做转换并返回转换结果。
这里在打印输出TF-IDF向量时,使用了break方法终止循环,实际上,在更多情况下会配合if条件做判断,当符合一定条件后,程序跳出循环体不再继续执行。
全角转半角:
def str_convert(content): ''' 将内容中的全角字符,包含英文字母、数字键、符号等转换为半角字符 :param content: 要转换的字符串内容 :return: 转换后的半角字符串 ''' new_str = '' for each_char in content: # 循环读取每个字符 code_num = ord(each_char) # 读取字符的ASCII值或Unicode值 if code_num == 12288: # 全角空格直接转换 code_num = 32 elif (code_num >= 65281 and code_num <= 65374): # 全角字符(除空格)根据关系转化 code_num -= 65248 new_str += unichr(code_num) return new_str
该函数用来将文本内容中的全角字符串转换为半角字符串,这样会避免在自然语言处理过程中由于字符不统一而导致的信息混乱问题。其输入参数如下:
content:要转换的字符串内容。
函数返回:转换后的半角字符串。
由于该功能是针对每一个字符做识别转换的,因此其过程比较慢。
该函数的具体定义如下:
定义一个空字符串对象new_str,用于存储转换后的结果。
使用for循环读取每个字符,然后使用ord方法读取字符的ASCII值或Unicode值赋值给code_num,接下来根据值做判断:当code_num值等于12288时,这是一个全角空格,此时直接将其值设置为32来转换成半角空格;当code_num值在[65281,65374]时,将其直接减去65248来转换为半角字符值。
数值转换完成后,使用unichr方法将其转换为字符,并通过直接相加的方法重新组合字符串。
最后返回转换后的新字符串。
相关知识点:全角字符串转半角字符串
全角指的是一个字符占2个标准字符的位置(例如中国汉字),半角指的是占1个标准字符的位置(例如普通的字符a)。在文本相关的处理过程中,半角和全角字符通常是数据预处理的必要过程。全角字符包含两类字符:
一类是特殊字符:空格,它的全角值十进制整数为12288,表示为十六进制结果是0x3000;而其半角十进制整数数值为32,十六进制结果是0x20。
一类是有规律的字符,这类字符的全角十进制整数的范围是[65281,65374],用十六进制表示的结果是[0xFF01,0xFF5E];其对应的半角十进制整数值为[33,126],用十六进制表示的结果是[0x21,0x7E]。
除了空格外,有规律的字符在半角和全角之间的差值是65248,因此我们可以直接在全角数值上减去65248即可得到半角数值。
例如,全角字符串“00527825CBD”转换为半角字符串的结果是“00527825CBD”。
在转换过程中,我们用到了2个新的函数:ord和unichr,这两个是配对使用的函数,前者用来从字符串读取对应的数值,后者用于将数值转换为unicode字符串。
并不是所有的全角字符都能被转换为半角字符,例如汉字是全角字符,占2个字符的位置,但无法被转换;只有英文字母、数字键、符号键等才能可以做全角和半角之间的转换。
解析文件内容:
def data_parse(data): ''' 从原始文件中解析出文本内容数据 :param data: 包含代码的原始内容 :return: 文本中的所有内容,列表型 ''' raw_code = BeautifulSoup(data, "lxml") # 建立BeautifulSoup对象 content_code = raw_code.find_all('content') # 从包含文本的代码块中找到content标签 content_list = [] # 建立空列表,用来存储每个content标签的内容 for each_content in content_code: # 循环读出每个content标签 if len(each_content) > 0: # 如果content标签的内容不为空 raw_content = each_content.text # 获取原始内容字符串 convert_content = str_convert(raw_content) # 将全角转换为半角 content_list.append(convert_content) # 将content文本内容加入列表 return content_list
该函数用来从原始文件中解析出文本内容数据。由于原始每个数据文件中都包含了类似XML格式的数据,因此需要将其中特定对象(content标签内的内容)解析出来。在2.2.5节我们介绍了使用xml库获取并解析xml数据的方法,在3.12.1节中介绍了使用bs4解析标准的HTML格式的数据,这里应用bs4来解析XML格式的数据。
函数输入参数如下:
data:包含代码的原始内容。
函数返回:文本中的所有内容,列表型。每个新闻为一个列表元素。
该函数的具体定义如下:
使用BeautifulSoup库建立处理对象raw_code,这里指定的解析库是lxml。
默认情况下,直接使用BeautifulSoup(data)会调用Python默认HTML解析器html.parser,这是Python内置标准库,该库执行速度适用。这里我们指定使用lxml库可以提供更快的解析速度。如果读者之前没有安装过该库,需要通过pip install lxml安装。
对raw_code使用find_all方法查找所有的content标签,将返回的列表结果赋值给content_code。
新建一个空列表对象content_list,用来存储每个content标签的内容。
使用for循环读出每个content标签,先判断标签是否为空,如果不为空,则将标签的text属性(标签内的内容)赋值给raw_content,然后调用str_convert函数将其中的全角转换为半角,最后将结果追加到列表content_list。
最后返回包含每条内容的列表。
步骤3 解压缩文件。
定义完各种功能函数后,从该步骤开始进入到应用过程。解压缩文件步骤是将tar.gz中的压缩文件提取出来。
if not os.path.exists('./news_data'): # 如果不存在数据目录,则先解压数据文件 print ('extract data from news_data.tar.gz...') tar = tarfile.open('news_data.tar.gz') # 打开tar.gz压缩包对象 names = tar.getnames() # 获得压缩包内的每个文件对象的名称 for name in names: # 循环读出每个文件 tar.extract(name, path='./') # 将文件解压到指定目录 tar.close() # 关闭压缩包对象
该过程主要定义如下:
if not os.path.exists('./news_data'):通过os.path.exists来判断指定目录是否存在,如果不存在则执行该之后的功能。
os.path.exists是对文件做操作的常用方法,基于该方法可以对文件做增、删、改等操作。而os.path则是更加实用的功能库,该库可以用来对文件或目录做查找、判断、合并、分裂等,通过更多的会配合目录或文件操作命令实现目录操作。
使用tarfile.open方法打开压缩包并建立操作对象tar。
使用tar.getnames()获得压缩包内的每个文件对象的名称。
通过for循环配合extract方法将每个文件提取到指定目录下面(path定义的目录)。
关闭压缩包对象。
步骤4 汇总所有内容。
该步骤可以将所有文件的content中的内容合并起来。
print ('walk files and get content...') all_content = [] # 总列表,用于存储所有文件的文本内容 for root, dirs, files in os.walk('./news_data'): # 分别读取遍历目录下的根目录、子目录和文件列表 for file in files: # 读取每个文件 file_name = os.path.join(root, file) # 将目录路径与文件名合并为带有完整路径的文件名 with open(file_name) as f: # 以只读方式打开文件 data = f.read() # 读取文件内容 all_content.extend(data_parse(data)) # 从文件内容中获取文本并将结果追加到总列表
该步骤功能实现如下:
建立空列表all_content,用于存储所有文件的文本内容。
然后两层for循环做目录下的所有文件遍历,第一层for循环使用os.walk方法读取指定目录下的路径和文件信息,第二层for循环读出文件列表中的每个文件。
在循环体内部,使用os.path.join方法将文件路径和文件名合并为带有完整路径的文件名,用于下面的文件内容读取。
使用with open()方法打开每次合并后的文件对象,然后基于该对象使用read方法读取其中内容。
调用data_parse功能对提取文本内容并将结果追加到列表中。
这里在读取文件时,没有使用标准的文件读取方法,而是使用了with open()方法,这种写法相对于之前的标准方法的实现结果是相同的,但是却更加简洁,因该方法无需使用close()方法关闭文件对象。因此,推荐读者更多使用这种方法。
相关知识点:利用os.walk遍历目录
在针对多文件做数据读取和应用操作时,通常需要程序自动遍历找到所有的文件,然后自动执行批量操作。此时通常会用到os.walk方法,该方法可以返回指定目录下所有的文件目录和文件的迭代器,该迭代器可以循环读取。os.walk参数如下:
walk(top, topdown=True, onerror=None, followlinks=False)
top:要遍历的根目录。
topdown:指定目录树是否自上而下产生。
onerror:默认情况下在os.walk方法执行时遇到错误会被忽略,也可以通过一个函数指定遇到错误时的方法,例如放弃、忽略并继续还是提示错误。
followlinks:设置为true,则通过软链接访问目录。
os.walk的迭代器是一个由文件夹路径dirpath、文件夹名称dirnames、文件名称filenames组成的三元组,其中文件夹路径dirpath是一个字符串,代表遍历的目录;文件夹名称dirnames是一个列表,代表文件夹路径下dirpath所有的文件夹名称,这些文件夹构成了可以做下次迭代的目录(dirpath);文件名称filenames是一个列表,代表的是一个个文件本身。
步骤5 获取每条内容的分词结果
该步骤用来从内容列表中读取每条内容,然后对其做中文分词。
print ('get word list...') words_list = [] # 分词列表,用于存储所有文件的分词结果 for each_content in all_content: # 循环读出每个文本内容 words_list.append(list(jieba_cut(each_content))) # 将文件内容的分词结果以列表的形式追加到列表
该步骤的实现比较简单,主要包括以下定义:
新建words_list用于存储所有文件的分词结果。
通过for循环读取all_content中的每条文本内容,然后调用jieba_cut做中文分词,分词结果直接使用list方法转换为列表,再使用append方法追加到总分词列表中。
步骤6 建立主题模型。
该步骤是本案例的核心应用过程。
print ('train topic model...') dic, corpus_tfidf, tfidf = text_pro(words_list, tfidf_object=None, training=True) # 训练集的文本预处理 num_topics = 3 # 设置主题个数 lda = models.LdaModel(corpus_tfidf, id2word=dic, num_topics=num_topics) # 通过LDA进行主题建模 print ('{:*^60}'.format('topic model review:')) for i in range(num_topics): # 输出每一类主题的结果 print (lda.print_topic(i)) # 输出对应主题
本步骤的主要定义如下:
调用定义的文本预处理函数text_pro,得到处理后的字典dic、稀疏矩阵corpus_tfidf和TF-IDF模型对象tfidf。除了返回的对象外,打印输出的内容如下:
分词列表转字典后的数据——token和word键值对:
****************token & word mapping review:**************** token:58875 -- word:铅锌 token:25710 -- word:楼兰 token:97812 -- word:平定 token:50462 -- word:供则 token:13113 -- word:考察队员
语料库词袋(bag of words)形式的列表——token和token计数列表:
********************bag of words review:******************** [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 2), (16, 1), (17, 2), (18, 1), (19, 1), (20, 1), (21, 1), (22, 1), (23, 1), (24, 1), (25, 1), (26, 2), (27, 1), (28, 1), (29, 1), (30, 1), (31, 1)]
TF-IDF向量稀疏矩阵——token和对应向量值:
********************TF-IDF model review:******************** [(0, 0.10154448591145282), (1, 0.16383481532598135), (2, 0.14602961468426073), (3, 0.16751768276692697), (4, 0.16778969587205647), (5, 0.168282481745965), (6, 0.16197667368712637), (7, 0.15736459689355045), (8, 0.16681622559479037), (9, 0.163124879458702), (10, 0.1653853043789113), (11, 0.16844765669812112), (12, 0.16660204914253687), (13, 0.14576561774317554), (14, 0.1662290891913951), (15, 0.30849126342177313), (16, 0.12365275311464316), (17, 0.2636835311342954), (18, 0.16703117734810868), (19, 0.11609101090194619), (20, 0.1685028172752526), (21, 0.15266091940783724), (22, 0.16833748902827933), (23, 0.16282320045073903), (24, 0.16409043499326897), (25, 0.16762633852828174), (26, 0.332245916102828), (27, 0.16501988564410103), (28, 0.1643986382302142), (29, 0.12399080729729553), (30, 0.1677351934753784), (31, 0.16762633852828174)]
通过num_topics设置主题个数为3,该变量会在建立以及打印输出中用到。使用models.LdaModel方法做主题建模,并设置如下参数:
corpus_tfidf:主题建模的数据集,来自预处理阶段的TF-IDF结果集。
id2word:分词字典,来自预处理阶段。
num_topics:要挖掘的主题个数,来自num_topics的定义。
并打印输出每个建模主题如下:
********************topic model review:********************* 0.003*"比赛" + 0.002*"搜狐" + 0.002*"登录" + 0.001*"欧洲杯" + 0.001*"是" + 0.001*"体育" + 0.001*"图" + 0.001*"球队" + 0.001*"球员" + 0.001*"北京" 0.002*"散布" + 0.002*"民族" + 0.002*"稳定" + 0.002*"标题" + 0.001*"犯罪" + 0.001*"社会" + 0.001*"谣言" + 0.001*"赌博" + 0.001*"教唆" + 0.001*"封建迷信" 0.003*"小区" + 0.002*"编号" + 0.002*"户型" + 0.002*"面积" + 0.002*"装修" + 0.002*"建筑面积" + 0.001*"楼层" + 0.001*"室" + 0.001*"有效期" + 0.001*"厅"
步骤7 主题预测。
主题模型除了可以针对特定数据集做主题分析外,还可以对新的文本做主题预测,常用于非监督式的主题归类(这点跟KMeans非常类似)。这里通过给定一个新的文本集article.txt,对其所属的主题做预测。
print ('topic forecast...') with open('article.txt') as f: # 打开新的文本 text_new = f.read() # 读取文本数据 text_content = data_parse(data) # 解析新的文本 words_list_new = jieba_cut(text_new) # 将文本转换为分词列表 corpus_tfidf_new = text_pro([words_list_new], tfidf_object=tfidf, training=False) # 新文本数据集的预处理 corpus_lda_new = lda[corpus_tfidf_new] # 获取新的分词列表(文档)的主题概率分布 print ('{:*^60}'.format('topic forecast:')) print (list(corpus_lda_new))
本步骤的定义过程如下:
使用with open方法打开文件article.txt并使用文件对象的read方法读取内容。
通过data_parse(data)解析出文件内容中的文本。
使用jieba_cut(text_new)将文本转换为分词列表。
调用text_pro对新文本做预处理,在函数参数传值过程中,需要注意以下几点:
[words_list_new]:数据集对象是列表形态,即使列表中只有一个列表元素。
tfidf_object:使用从训练阶段返回的TF-IDF对象tfidf。
training:设置为False使用预测阶段的功能。
通过lda[corpus_tfidf_new]获取新内容的主题预测概率分布,将其转换为列表后打印输出。整个输出内容如下:
topic forecast... ****************token & word mapping review:**************** token:0 -- word:未能 token:1 -- word:身着 token:2 -- word:内 token:3 -- word:来自 token:4 -- word:成为 ********************bag of words review:******************** [(0, 1), (1, 1), (2, 1), (3, 1), (4, 2), (5, 4), (6, 2), (7, 1)... (185, 1), (186, 1)] **********************topic forecast:*********************** [[(0, 0.65730750776590874), (1, 0.30406664373195513), (2, 0.038625848502136163)]]
由于“bag of words review”中的内容较长,这里将其中的部分内容省略,只保留首尾数据示例。
8.7.5 案例数据结论
从主题建模得到的结果看:
(1)第一类主题
0.003*"比赛"+0.002*"搜狐"+0.002*"登录"+0.001*"欧洲杯"+0.001*"是"+0.001*"体育"+0.001*"图"+0.001*"球队"+0.001*"球员"+0.001*"北京"
主题中权重比较高的词语是比赛、搜狐、登录等,权重值分别为0.003、0.002和0.002;其次是欧洲杯、体育、球队等,权重值均为0.001。因此大体可以判断该主题是与比赛、体育相关。
(2)第二类主题
0.002*"散布"+0.002*"民族"+0.002*"稳定"+0.002*"标题"+0.001*"犯罪"+0.001*"社会"+0.001*"谣言"+0.001*"赌博"+0.001*"教唆"+0.001*"封建迷信"
主题中权重比较高的词语是散布、民族、稳定、标题等,权重值均是0.002;其次是犯罪、社会、谣言等,权重值均为0.001。因此大体可以判断该主体与政治、社会、新闻等主题相关。
(3)第三类主题
0.003*"小区"+0.002*"编号"+0.002*"户型"+0.002*"面积"+0.002*"装修"+0.002*"建筑面积"+0.001*"楼层"+0.001*"室"+0.001*"有效期"+0.001*"厅"
主题中权重比较高的词语是小区、编号、户型、面积、装修、建筑面积等,权重值均为0.002;其次是楼层、室育、有效等,权重值均为0.001。因此大体可以判断该主题是与生活、社区、民生主题相关。
对新主题的预测上,通过结果可以发现,该数据集属于第一、二、三主题的概率是65.7%、30.4%、3.9%。因此新数据集更偏向于第一主题,即比赛、体育类话题。读者可查看源文件,该文件确实属于该内容方向。
8.7.6 案例应用和部署
对于此类以文本挖掘为主的分析类案例,后期的主要应用方向包括:
从各个类别的主题中提取关键字,并将关键字作为各个主题的SEO关键字优化主题;
不断增加新的文本数据,然后将每次的主题关键字做对比,查找分析新出现的主题关键字,建立对于特定主题的分析和后续内容运营机制;
基于历史主题建模结果做对比,发现各个主题中的新词、新趋势和新话题点;
基于主题关键字,建立或优化主题页的自动关键字和自动摘要信息;
基于具有显著性的关键字(较高权重),将所有文章进行重新类别划分或优化,使主题间的关联性和话题紧密型更强。
8.7.7 案例注意点
本案例实施过程中,需要注意以下几点:
在做预测集应用时,所有的文本预处理过程都需要重新做一遍,但TF-IDF模型不需要重新做,只需要应用训练好的模型即可。
主题类别的划分,严重依赖于中文分词的结果。本案例中,只保留具有特定意义的词语,而“有意义”的认知依赖于具体应用环境;通常情况下,名词、动词等类型的词语在主题提炼中更具有显著性意义。
新的预测集在做文本预处理时,需要保持跟训练集相同的格式(此案例中都是嵌套列表)。
如果有大量的文本数据集,可以将训练好的LDA(以及其他模型)持久性保存到硬盘,使用save和load方法可以实现。这样可以避免所有数据对象都存储在内存中,由于数据计算容量的增加导致内存溢出等问题。
8.7.8 案例引申思考
(1)如何提高结巴分词效率
案例中的结巴分词模块,对于大文本下的分词效率比较低。结巴分词支持并行分词,它可以将目标文本按行分隔后,把各行文本分配到多个Python进程并行分词然后归并结果,从而获得分词速度的提升。并行分词基于Python自带的multiprocessing模块,但是目前暂不支持Windows。
(2)关于有效主题数量的确定
主题模型中关于主题个数的确定,跟KMeans算法中的K非常类似,如果是针对新的文本集,在没有任何先验经验的前提下要获得有意义的主题是比较困难的,这需要读者通过多次实验获的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论