全文共3480字,预计阅读时长7分钟
在解决自然语言处理的问题上,有一种文本挖掘的方法叫做主题模型,这是提取主题时一项极其有用的技术,那么什么是主题模型?何时使用主题模型?在Python中利用潜在语义分析来解决主题模型时,又应该注意哪些问题?读完了本文,相信你一定会有最实在的收获!
前言
你有没有去过维护得相当完善的图书馆?那些图书管理员非常让人佩服,他们把图书按照名称、内容或主题进行归类,一切都管理得井井有条。但是如果你扔给他们上千本图书,然后让他们按照书本的类型来整理好,他们可能一天都做不完,更不必说在一个小时之内了。
但是,如果这些书都是电子文本的话,整理工作可能就是几秒钟的事情,无需任何人力。自然语言处理万岁!
先来看一下下面的文本片段:
参照有底色的文本,可以看到一共有三个主题(或者概念)——主题1、主题2和主题3。一个好的主题模型能够辨别相似的词组,并把它们归为一类。上面的例子中最明显的主题是主题2,主要讲伪造影像的内容。
有意思吧?好!本文介绍了一个叫做主题模型的文本挖掘方法。这是提取主题时一项极其有用的技术,在应对自然语言处理问题的时候也非常常见。
提示:强烈建议你阅读这篇文章以对奇异值分解(SVD)和UMAP等概念进行了解(https://www.analyticsvidhya.com/blog/2018/08/dimensionality-reduction-techniques-python/)。本文是建立在这些概念之上的,因此先学习它们有利于巩固我们对基础概念的理解。
目录
什么是主题模型?
何时使用主题模型?
潜在语义分析(Latent Semantic Analysis, LSA)
在Python使用LSA
4.1 数据读取和检视
4.2 数据预处理
4.3 文本—词语矩阵
4.4主题模型
4.5 主题可视化
LSA的优缺点
主题模型的其他技术
1.什么是主题模型?
主题模型是一种无监督技术,用来发现各种文本文档中的主题。这些主题本质上是抽象的,也就是说彼此相关的单词会形成主题。 与此同时,单个文档中可以有多个主题。本文中暂时将主题模型理解为黑盒子,如下图所示:
这个黑盒子(也就是主题模型)把相关的词组划分为不同的类群,称之为主题。这些主题在文本中有特定的分布,每个主题都可以用不同比例的单词组合来定义。
2.何时使用主题模型?
回想一下之前提到的整理图书的任务。现在想象一下,你需要对电子文档来进行分类。当然,如果文档比较少的话,你可以手动完成这个任务。但是如果文档特别多的话怎么办?
这时候就要用自然语言处理技术了。而对于这个任务来说,将使用主题模型来完成。
主题模型可以帮助我们对海量的文本数据进行探索,对词组进行聚类,找到文本之间的相似性,并发现抽象的主题。如果你觉得这些任务还不够有挑战的话,主题模型还可以在搜索引擎中找到与搜索文本匹配的结果。是不是有点意思了?让我们继续深入探讨!
3.潜在语义分析(Latent Semantic Analysis, LSA)
所有语言都会有自身的复杂性和微妙特征,机器是难以捕捉这些内容的(有的时候人类自己也难以分辨)。比方说,不同的单词可能会有相同的含义,而同样的单词又可能有不同的含义。
让我们来看下面两个句子:
1. I liked his lastnovelquite a lot.
2. We would like to go for anovelmarketing campaign.
第一句话中,“novel”指代的是一本书,而第二句话中它表示新奇的、新颖的。
我们可以通过上下文轻易地推断这两个词的含义,但是机器就捕捉不到这个概念因为它不能理解单词所使用的语境。这时候就需要用到潜在语义分析了,它可以基于词组之间的上下文来揣摩背后的意思,也就是我们说的主题。
因此,单纯地把词组映射到文档中不一定有效果,我们需要的是搞懂词语背后的概念和主题。潜在语义分析就是能够找到隐藏主题的一种方法,现在让我们来深入探讨潜在语义分析的内部工作机制。
潜在语义分析的实现步骤
比方说我们有m个文档,文档中一共有n个唯一的词,我们要从所有文档中提取出k个主题。这里k表示主题的数量,是由用户自己定义的。
构造一个形如m * n的文档—词语矩阵,其中包含有TF-IDF分值。
然后,我们会把上述的矩阵用奇异值分解(SVD)的方法降到k维。
奇异值分解(SVD)把矩阵分解为三个矩阵。比如我们想要用奇异值分解(SVD)来降解矩阵A,那么我们会得到矩阵U、矩阵S和矩阵VT(矩阵V的转置矩阵)。矩阵Uk(文档—词组矩阵)的每一行都是文档的向量表示。这些向量的长度为k,也就是我们设定的主题数量。词组的向量表示可以在Vk(词语—主题矩阵)中找到。
这样一来,奇异值分解(SVD)把我们数据中的每个文档和词组都进行了向量化,每个向量的长度都是k。我们可以结合余弦相似度的方法,利用这些向量来找相似的词组和文档。
4.在Python中使用潜在语义分析
下面我们介绍如何在Python中利用潜在语义分析来解决主题模型的问题。打开Python之后,可以按照我下面提到的步骤开始运行代码。
4.1 数据读取和检视
首先要加载下面的包:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
pd.set_option("display.max_colwidth", 200)
本文中,我们会用到sklearn的’20 Newsgroup’数据集。您可以在这里下载数据集,并运行代码。
from sklearn.datasets import fetch_20newsgroups
dataset = fetch_20newsgroups(shuffle=True, random_state=1, remove=('headers', 'footers', 'quotes'))
documents = dataset.data
len(documents)
输出: 11,314
dataset.target_names
['alt.atheism',
'comp.graphics',
'comp.os.ms-windows.misc',
'comp.sys.ibm.pc.hardware',
'comp.sys.mac.hardware',
'comp.windows.x',
'misc.forsale',
'rec.autos',
'rec.motorcycles',
'rec.sport.baseball',
'rec.sport.hockey',
'sci.crypt',
'sci.electronics',
'sci.med',
'sci.space',
'soc.religion.christian',
'talk.politics.guns',
'talk.politics.mideast',
'talk.politics.misc',
'talk.religion.misc']
数据集包含来自20个不同新闻媒体的11,314份文本文档。
4.2 数据预处理
开始,我们要尽可能对文本数据进行清洗。基本原则就是利用正则表达式,用replace(“[^a-zA-Z#]”)代码把除了字母与空格之外的所有字符清除掉。然后我们会排除一些短的词,因为它们往往不包含有用的信息。最后,我们把所有文本都转为小写字母,这样识别对大小写就不敏感了。
news_df = pd.DataFrame({'document':documents})
# removing everything except alphabets`
news_df['clean_doc'] = news_df['document'].str.replace("[^a-zA-Z#]", " ")
# removing short words
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: ' '.join([w for w in x.split() if len(w)>3]))
# make all text lowercase
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: x.lower())
停止词的删除是有必要的,因为它们一般都是杂乱无章而不表达任何信息。停止词包含‘it’, ‘they’, ‘am’, ‘been’, ‘about’, ‘because’, ‘while’等。
要从文档中去除停止词,我们首先要对文档进行标记字符串,也就是把字符串切分为单个标记或单词。去除停止词之后我们会把这些内容重新连接起来。
from nltk.corpus import stopwords
stop_words = stopwords.words('english')
# tokenization
tokenized_doc = news_df['clean_doc'].apply(lambda x: x.split())
# remove stop-words
tokenized_doc = tokenized_doc.apply(lambda x: [item for item in x if item not in stop_words])
# de-tokenization
detokenized_doc = []
for i in range(len(news_df)):
t = ' '.join(tokenized_doc[i])
detokenized_doc.append(t)
news_df['clean_doc'] = detokenized_doc
4.3 文本—词语矩阵
这是创建主题模型的第一步。我们会用sklearn的TfidfVectorizer函数来创建包含1000个词语的文本-词语矩阵。
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(stop_words='english',
max_features= 1000, # keep top 1000 terms
max_df = 0.5,
smooth_idf=True)
X = vectorizer.fit_transform(news_df['clean_doc'])
X.shape # check shape of the document-term matrix
(11314, 1000)
我们其实可以使用所有的词语来创建矩阵,但是这会浪费大量的计算时间与资源。因此,我们将特征的数量限制为1000。如果你有足够的计算资源,我建议你可以把所有的词语都涵盖进去。
4.4 主题模型
下一步是把每个词语和文档用向量表示。我们会用sklearn的TruncatedSVD函数把文档—词语矩阵降解为多个矩阵。
因为数据来自20个不同的新闻媒体,我们就设定有20个主题。可以用n_components参数来对主题数量进行设定。
from sklearn.decomposition import TruncatedSVD
# SVD represent documents and terms in vectors
svd_model = TruncatedSVD(n_components=20, algorithm='randomized', n_iter=100, random_state=122)
svd_model.fit(X)
len(svd_model.components_)
20
svd_model的要素(components)就是我们的主题,我们可以利用svd_model.components来获取这些主题。最后,让我们在这20个主题中,输出每个主题中比较重要的单词,看看我们的模型结果如何。
terms = vectorizer.get_feature_names()
for i, comp in enumerate(svd_model.components_):
terms_comp = zip(terms, comp)
sorted_terms = sorted(terms_comp, key= lambda x:x[1], reverse=True)[:7]
print("Topic "+str(i)+": ")
for t in sorted_terms:
print(t[0])
print(" ")
Topic 0: like know people think good time thanks
Topic 1: thanks windows card drive mail file advance
Topic 2: game team year games season players good
Topic 3: drive scsi disk hard card drives problem
Topic 4: windows file window files program using problem
Topic 5: government chip mail space information encryption data
Topic 6: like bike know chip sounds looks look
Topic 7: card sale video offer monitor price jesus
Topic 8: know card chip video government people clipper
Topic 9: good know time bike jesus problem work
Topic 10: think chip good thanks clipper need encryption
Topic 11: thanks right problem good bike time window
Topic 12: good people windows know file sale files
Topic 13: space think know nasa problem year israel
Topic 14: space good card people time nasa thanks
Topic 15: people problem window time game want bike
Topic 16: time bike right windows file need really
Topic 17: time problem file think israel long mail
Topic 18: file need card files problem right good
Topic 19: problem file thanks used space chip sale
4.5 主题可视化
要知道我们的主题是否有特色,就需要进行可视化。当然,我们无法对三个维度以上的信息进行可视化。但是利用主成分分析(PCA)或t-SNE,我们可以把高维数据放在低维中进行可视化展示。这里我们会用一个相对较新的技术,叫做UMAP (Uniform Manifold Approximation and Projection)。
import umap
X_topics = svd_model.fit_transform(X)
embedding = umap.UMAP(n_neighbors=150, min_dist=0.5, random_state=12).fit_transform(X_topics)
plt.figure(figsize=(7,5))
plt.scatter(embedding[:, 0], embedding[:, 1],
c = dataset.target,
s = 10, # size
edgecolor='none'
)
plt.show()
通过上面的图,我们可以看到结果是比较漂亮的。每个点代表了一个文档,而不同的颜色代表20个新闻媒体,看来我们的LSA模型非常有效。可以改变一下UMAP的参数,看看图片会有什么变化。
文中所有代码都可以在GitHub中找到。
(https://github.com/prateekjoshi565/latent_semantic_analysis)
5.LSA的优缺点
上面的例子中我们可以看到潜在语义分析的威力,但是它还是有自身局限性的。我们需要了解LSA的优缺点,这样我们才知道什么时候选用它,什么时候应该尝试别的方法。
优点:
LSA速度快,容易实现。
效果好,比平面向量空间模型要好得多。
缺点:
它是一个线性模型,因此在非线性依赖关系的数据集中表现不佳。
LSA假设词语在文档中呈正态分布,但不是所有问题都满足这个假设。
LDA需要用到SVD,这是计算密集型的运算,在新数据加入后难以进行更新。
6.主题模型的其他技术
除了LSA之外,还有其他高级有效的主题模型技术,比如LDA和lda2Vec。我们还写过一篇介绍LDA的好文章,可以给大家提供参考。Lda2vec是一个高级得多的主题模型方法,它是基于word2vec单词嵌入的。
结束语
这篇文章中我分享了自己的学习收获。主题模型是一个非常有意思的东西,它能帮助你处理许多文本数据集。因此,我建议大家利用本文的代码来解决其他数据集的问题。享受文本挖掘吧!
留言 点赞 发个朋友圈
我们一起分享AI学习与发展的干货
编译组: 黄天元、胡婷
领取专属 10元无门槛券
私享最新 技术干货