你去过秩序良好的图书馆吗?我总是因为图书馆管理员通过名称,内容和其他主题等管理好所有的书籍而感到印象深刻。但如果你让图书馆管理员将成千上万的书按照流派分门别类,他们也许至少需要耗费一整天的时间,而不仅仅是一两个小时!
然而,如果这些书是以数字格式出现的,就简单多了,对吧?所有的安排似乎只需要几秒钟的时间,而不需要任何人工努力。这就涉及到自然语言处理(Natural Language Processing,NLP)。
看看下面的文字片段:
如图中高亮文本所示,有三个主题(或概念)——主题1、主题2和主题3。一个好的主题模型将识别相似的单词并把它们放在一个组或主题之下。上面的例子中最重要的主题是主题2,这表明这篇文章主要是关于fake video。
在本文中,我们将学习主题建模的文本挖掘方法。这是一个用来提取主题的非常有用的技术,一个你会工作很多,当面对NLP的挑战。
注意:我强烈推荐通过本文了解SVD和UMAP等术语。它们在本文中被利用,所以对它们有一个基本的理解将有助于巩固这些概念。
目录表
1.什么是主题模型?
2.主题建模是什么时候使用的?
3.潜在语义分析(LSA)综述
4.Python中LSA的实现
- 数据读取与检验
- 数据预处理
- 文档项矩阵
- 主题建模
- 主题可视化
5.LSA的利弊
6.主题建模的其他技术
1.什么是主题模型?
主题模型可以被定义为一种无监督的技术,以发现跨各种文本文档的主题。这些主题本质上是抽象的,即相互关联的词语构成主题。类似地,在单个文档中可以有多个主题。暂时,让我们把一个主题模型理解为一个黑盒子,如下图所示:
这个黑箱(主题模型)形成了相似的和相关的词的簇,这些词被称为主题。这些主题在文档中具有一定的分布,每个主题都由它所包含的不同单词的比例来定义。
2.主题建模是什么时候使用的?
回忆一下我们之前看到的把相似的书放在一起的例子。现在假设你必须对一些数字文本文档执行类似的任务。只要文档的数量是可管理的(即不太多),就可以手动完成这一任务。但是当这些数字文本文件数量过多呢?
这就要用到NLP技术了。对于这个特定的任务,主题建模是我们将要使用的技术。
主题建模有助于探索大量的文本数据、发现词组、文档之间的相似性继而发现抽象主题。似乎这些原因还不够令人信服,主题建模也被用在搜索引擎中,让搜索字符串与结果匹配。
3.潜在语义分析(LSA)综述
所有语言都有它们自己的复杂性和细微差别,这对于机器来说很难捕捉(有时人类也会误解)这可以包括表示相同事物的不同单词,以及拼写相同但含义不同的单词。
例如,考虑下面两个句子:
- 我很喜欢他的最后一部小说(novel)。
- 我们想进行一次新的(novel)营销活动。
在第一句话中,“novel”一词指的是一本书,而在第二句中,它意味着新的或新鲜的。
我们可以很容易地区分这些单词,因为我们能够理解这些单词后面的上下文。然而,机器将无法捕获这个概念,因为它无法理解单词使用的上下文。这就是潜在语义分析(LSA)发挥作用的地方,因为它试图利用上下文来捕获隐藏的概念,也称为主题。
因此,简单地将单词映射到文档不会有什么实质性的帮助。我们真正需要的是找出隐藏的概念或单词背后的主题。LSA是一种可以找到这些隐藏主题的技术。现在让我们深入研究LSA的内部工作。
LSA实施步骤
比方说,我们有m个文本文档,有n个总的唯一术语(单词)。我们希望从文档中的所有文本数据中提取k个主题。主题的数量k必须由用户指定。
- 生成具有TF-IDF分数的形状m x n的文档项矩阵。
- 然后,我们将使用奇异值分解(SVD)将上述矩阵的维数减少到k(所需主题的否)维。
- 奇异值分解将矩阵分解为三个矩阵。假设我们想用SVD分解矩阵A。它将被分解成矩阵U、矩阵S和
(矩阵V的转置)。
矩阵 的每一行(document-term matrix,DTM矩阵)是对应文档的向量表示。这些向量的长度是k,这是所需主题的数目。我们的数据中的术语的矢量表示可以在矩阵(term-topic矩阵)中找到。
因此,SVD为我们的数据提供了每个文档和术语的向量。每个向量的长度是k,然后我们可以使用这些向量使用余弦相似性方法找到相似的单词和类似的文档。
4.Python中LSA的实现
是时候启动Python并了解如何在主题建模问题中实现LSA。一旦您的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)
输出:11314
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']
数据集有11314个文本文档分布在20个不同的新闻组中。
4.2 数据预处理
首先,我们将尽可能地清理我们的文本数据。其思想是使用正则表达式替换(“[^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”、“them”、“am”、“be”、“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个术语的DTM矩阵。
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 主题建模
下一步是将每一个术语和文档表示为向量。我们将使用DTM矩阵,并将其分解成多个矩阵。我们将使用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 的组件是我们的主题,我们可以使用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 主题可视化
我们需要可视化主题模型以找出我们的主题是多么的不同。当然,我们不能可视化超过3维,但是像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存储库中找到。
5. LSA的利弊
正如我们在上面看到的,潜在语义分析是非常有用的,但是它确实有其局限性。了解LSA的利弊是很重要的,这样你就可以知道何时使用杠杆和何时尝试其他东西。
利:
- LSA是快速和容易实现的。
- 它给出了不错的结果,比朴素的向量空间模型要好得多。
弊:
- 由于它是一个线性模型,它可能没有很好地对具有非线性相关性的数据集。
- LSA假定文档中的术语的高斯分布,这对于所有问题可能不是真的。
- LSA涉及SVD,它是计算密集型的,并且随着新数据的出现而难以更新。
6.主题建模的其他技术
除了LSA,还有其他高级和高效的主题建模技术,如潜在狄利克雷分配(Latent Dirichlet Allocation ,LDA)和lda2vec。我们还有一篇关于LDA的精彩文章。Ida2vec是一个基于word2vec 词嵌入的更高级的主题建模。
7.小结
主题建模是一个非常有趣的话题,它为您提供了处理许多文本数据集技巧。因此,我敦促大家使用本文中给出的代码,并将其应用到不同的数据集。
翻译:徐大白
注意:本文归作者所有,未经作者允许,不得转载