文本大数据时代,每个开发人员都需要了解如何分析文本

现在 , 使用Python和开源工具可以非常方便地进行文本分析 , 因此在这个文本大数据时代 , 每个开发人员都需要了解如何分析文本 。
推荐相关图书:《自然语言处理与计算语言》
本书从学习数据清洗开始 , 学习如何执行计算语言学算法 , 然后使用真实的语言和文本数据、使用Python来探索NLP和深度学习的更高级课题 。 我们还会学习使用开源工具来标记、解析和建模文本 。 读者将掌握优秀框架的实战知识 , 以及怎样为主题模型选择类似Gensim的工具 , 怎样通过Keras进行深度学习 。
谁适合读这本书?希望读者对Python有一定的了解 , 如果没有也没关系 , 本书会介绍一些Python的基础知识 。 此外 , 了解基本的统计学方法也大有裨益 。 鉴于本书主要内容涉及自然语言处理 , 所以了解基本语言学的知识还是非常有帮助的 。
本书主要内容第1章 , 什么是文本分析 。 当今技术的发展使得开发人员可以方便地从互联网获取海量的文本数据 , 利用强大、免费的开源工具来进行机器学习、计算语言学方面的研究 。 这个领域正在以前所未有的速度发展 。 本章将详细讨论什么是文本分析 , 以及学习和理解文本分析的动机 。
第2章 , Python文本分析技巧 。 第1章中提到 , 本书将把Python作为工具 , 因为它是一种易用且功能强大的编程语言 。 本章将介绍用于文本分析的Python基础知识 。 为什么Python基础知识很重要?虽然我们希望读者具备一定的Python和高中数学知识 , 但部分读者也许已经很久没有编写Python代码了 。 还有一部分Python开发人员的经验是基于Django之类的Web框架之上 , 这与文本分析和字符串处理所需要的技能有所不同 。
第3章 , spaCy语言模型 。 虽然第2章已经介绍了文本分析的概念 , 但没有具体讨论构建文本分析流程的任何技术细节 。 本章将介绍spaCy的语言模型 。 这将是文本分析的第一步 , 也是NLP流程中的第一个组件 。 此外 , 本章还将介绍spaCy开源库 , 以及如何使用spaCy来帮助开发人员完成文本分析任务 , 并讨论一些更强大的功能 , 如POS标记和NER 。 本章将用一个实例来说明如何使用spaCy快速有效地预处理数据 。
第4章 , Gensim:文本向量化、向量变换和n-grams的工具 。 虽然前面的章节已经带领读者处理过原始文本数据 , 但是任何机器学习或信息检索相关算法都不会把原始文本作为输入格式 。 所以本章将使用一种称为向量的数据结构来帮助算法模型理解文本 , 并选择Gensim和scikit-learn作为转换工具 。 在开始向量化文本的同时 , 还会引入预处理技术 , 比如bi-grams、tri-grams和n-grams 。 通过词频可以过滤掉文档中不常见的单词 。
第5章 , 词性标注及其应用 。 第1章和第2章介绍了文本分析和Python , 第3章和第4章帮助读者为更高级的文本分析设置代码 。 本章将讨论第一种高级NLP技术:词性标注(POS-tagging) 。 我们将研究什么是词性 , 如何识别单词的词性 , 以及怎样使用词性标签 。
第6章 , NER标注及其应用 。 上一章介绍了如何使用spaCy来完成词性标注 。 本章将探讨另一个有趣的用法:NER标注 。 本章将从语言和文本分析的角度来讨论什么是NER标注 , 并详细说明它的使用示例 , 以及如何用spaCy训练自己的NER标注 。
第7章 , 依存分析 。 第5章和第6章中介绍了spaCy的NLP如何执行各种复杂的计算语言学算法 , 如POS标注和NER标注 。 不过 , 这并不是所有的spaCy包 , 本章将探讨依存分析的强大功能 , 以及如何在各种上下文和应用场景中使用它 。 在继续使用spaCY之前 , 我们将研究依存分析的理论基础 , 并训练一个依存分析模型 。
第8章 , 主题模型 。 到目前为止 , 我们学习了一些计算语言学算法和spaCy方面的知识 , 并了解了如何使用这些计算语言学算法来标记数据 , 以及理解句子结构 。 虽然利用这些算法可以捕获文本的细节 , 但仍然缺乏对数据的全面了解 。 在每个语料库中 , 哪些词比其他词出现得更频繁?是否可以对数据进行分组或找到潜在主题?本章将尝试解答这些问题 。
第9章 , 高级主题建模 。 在前一章中 , 我们见识了主题模型的威力 , 并理解和探索了数据的直观方式 。 本章将进一步探讨这些主题模型的实用性 , 以及如何创建一个更高效的主题模型 , 更好地封装可能出现在语料库中的主题 。 主题建模是理解语料库文档的一种方式 , 它为开发人员分析文档提供了更多的发挥空间 。
第10章 , 文本聚类和文本分类 。 前一章介绍了主题模型 , 以及它组织和理解文档及其子结构的过程 。 本章将继续讨论新的文本机器学习算法 , 以及两个特定的任务——文本聚类和文本分类 , 探讨这两个算法的直观推理 , 以及如何使用流行的Python机器学习库scikit-learn来建模 。
第11章 , 查询词相似度计算和文本摘要 。 一旦文本可以向量化 , 就可以计算文本文档之间的相似性或距离 。 这正是本章要介绍的内容 。 现在业界存在多种不同的向量表示技术 , 从标准的单词包表示、TF-IDF到文本文档的主题模型表示 。 本章还将介绍关于如何用Gensim实现文本摘要和关键词提取的知识 。
第12章 , Word2Vec、Doc2Vec和Gensim 。 前面的章节曾经多次讨论向量化这一课题——如何理解向量化 , 以及如何使用数学形式表示文本数据 。 我们所使用的所有机器学习方法的基础都依赖于这些向量表示 。 本章将更进一步 , 使用机器学习技术来生成单词的向量化表示 , 从而更好地封装单词的语义信息 。 这种技术俗称为词嵌入 , Word2Vec和Doc2Vec是该技术的两种主流变体 。
第13章 , 使用深度学习处理文本 。 到目前为止 , 我们已经探索了机器学习在各种上下文中的应用 , 比如主题建模、聚类、分类、文本摘要 , 甚至POS标注和NER标注都离不开机器学习 。 本章将介绍机器学习的前沿技术之一:深度学习 。 深度学习是机器学习的一个分支 。 该技术受生物结构的启发 , 通过神经网络来生成算法和结构 。 文本生成、文本分类和单词嵌入领域都是深度学习可结合的领域 。 本章将学习深度学习的基础知识 , 以及一个文本深度学习模型实现的例子 。
第14章 , 使用Keras和spaCy进行深度学习 。 前一章介绍了文本的深度学习技术 , 并尝试使用神经网络生成文本 。 本章将更深入地研究文本的深度学习 , 特别是如何建立一个能够进行文本分类的Keras模型 , 以及如何将深度学习融入到spaCy的流程中 。
第15章 , 情感分析与聊天机器人 。 到目前为止 , 我们已经掌握了开始文本分析项目所需的基本技能 , 可以尝试更为复杂的项目 。 其中 , 有两个文本分析场景在之前没有涉及 , 但其中的很多概念都很常见:情绪分析和聊天机器人 。 本章将作为一个导引 , 指导读者独立完成上述两个应用 。 本章不提供构建聊天机器人或情感分析的完整代码 , 而是把重点放在各种相关技术原理的介绍上 。
样章试读:
第10章文本聚类和文本分类上一章探讨了如何使用主题模型更好地组织和理解文档 。 本章将继续讨论机器学习算法中的聚类和分类任务及其工作原理 , 以及如何使用流行的Python机器学习库scikit-learn来执行这些任务 , 本章介绍的主题如下:
文本聚类;文本分类 。 10.1文本聚类此前 , 我们通过分析文本来更好地理解文本或语料库是由什么组成的 , 比如POS标注或NER标注会告诉我们文档中出现了什么样的单词;主题模型会告诉我们隐藏在文本中的潜在主题是什么 。 当然 , 开发人员也可以使用主题模型来对文档进行聚类 , 但这并不是主题模型的强项 , 贸然尝试并期望取得比较好的效果 , 是不切实际的 。 注意 , 由于主题建模的目的是在语料库中查找隐藏的主题 , 而不是将文档分组 , 因此目前没有特别好的办法对其进行聚类方面的优化 。 例如 , 在执行主题建模之后 , 文档可以由主题1、2、3组成 , 占比分别为30%、30%和40% , 这些信息还不足以用来进行聚类 。
下面我们开始介绍两种更偏向定量分析的机器学习算法:聚类和分类 。 聚类是一种流行的机器学习任务 , 经典的聚类任务中所使用的技术也可以用于文本 。 顾名思义 , 聚类是将同一组中的数据点分组或聚类的任务 , 其中同一组中的点比其他组中的点更相似 。 扩展开来讲 , 数据点可以是一篇文档 , 或者是一个单词 。 聚类是一个无监督的学习问题 。 在开始将数据点分配给集群或组之前 , 我们并不知道它们的类别(尽管我们可能知道会找到什么) 。
分类任务与聚类任务有些类似 , 是通过包含已知样本类别(或实例)的训练数据集 , 来确定未知样本属于一组类别中的哪一个类别 。 例如 , 将收到的电子邮件分配到垃圾邮件或非垃圾邮件类 , 或者将报纸文章分配到指定的类或组 。
一个著名的聚类或分类任务的数据集叫作Iris , 该数据集包含花的花瓣长度和类别信息 。 另一个非常流行的数据集叫作MNIST , 它包含手写数字 , 这些数字应该按照它所代表的数字进行分类 。
文本聚类遵循标准聚类问题所遵循的大多数原则 , 但是文本分析领域的维数实在太多了 。 例如 , 在Iris数据集中 , 只有4个特征可以用来标识类或集群 。 而对于文本 , 在对问题进行建模时 , 我们必须处理整个词汇表 。 当然 , 我们将尽力使用一些技术 , 如SVD、LDA和LSI来减少维度 。
前几章中大量使用Gensim以及计算语言学的spaCy来执行计算语言学的量化任务 。 从现在开始 , 我们将开始使用一个更传统的机器学习库scikit-learn 。 本书的前面几章已经介绍过部分scikit-learn的内容 。
研究聚类和分类算法 , 我们就不得不提到Word2Vec和Doc2Vec这两种将单词和文档表示为向量方法 。 这是一种新的关于单词和文档的向量表示方法 , 比此前涉及的几种算法更为复杂 。 我们将在第12章中再次探讨Word2Vec和Doc2Vec , 并使用它们进行聚类和分类 。
10.2聚类前的准备工作最重要的准备工作仍旧是预处理步骤 , 即删除停用词和词干化 。 然后就是将文档转换为向量表示 。
本节使用scikit-learn来完成聚类、分类和预处理这三个任务 。 首先需要确定使用哪个数据集 。 选择有很多 , 在这里我们选择目前最流行的20个新闻组数据集 。 由于数据集本身内置于scikit-learn之中 , 所以加载和使用也很方便 。
读者可以参考课后JupyterNotebook的聚类分类示例 , 我们从中摘取了代码片段来解释该过程 。
加载数据集的代码如下:
fromsklearn.datasetsimportfetch_20newsgroupscategories=['alt.atheism','talk.religion.misc','comp.graphics','sci.space',]dataset=fetch_20newsgroups(subset='all',categories=categories,shuffle=True,random_state=42)labels=dataset.targettrue_k=np.unique(labels).shape[0]data=https://pcff.toutiao.jxnews.com.cn/p/20200903/dataset.data上述代码使用import语句访问20NG数据集 , 在本例中 , 我们只选取了4个类别 。 通过选择所有子集来创建数据集 , 同时也对数据集进行梳理 , 保证其状态随机 。 然后将文本数据转换成机器学习算法可以理解的形式向量 。
这里使用的是scikit-learn内置的TfidfVectorizer类来简化工作:
fromsklearn.feature_extraction.textimportTfidfVectorizervectorizer=TfidfVectorizer(max_df=0.5,min_df=2,stop_words='english',use_idf=True)X=vectorizer.fit_transform(data)X对象是输入向量 , 包含数据集的TF-IDF表示 。 在TF-IDF转换时 , 我们处理的仍是高维数据 。 为了更好地理解数据的性质 , 我们将其进行可视化处理 。 我们可以使用PCA(主成分分析)将数据集中的数据映射到二维空间 。 PCA可以查找出数据集中的无关成分(数学术语叫作线性不相关) 。 通过识别高维数据集中的不相关成分 , 可以有效地把数据降维 。 当然本例的主要目的还是可视化 , 在聚类场景中我们会采用其他降维技术:
fromsklearn.decompositionimportPCAfromsklearn.pipelineimportPipelinenewsgroups_train=fetch_20newsgroups(subset='train',categories=['alt.atheism','sci.space'])pipeline=Pipeline([('vect',CountVectorizer()),('tfidf',TfidfTransformer()),])X_visualise=pipeline.fit_transform(newsgroups_train.data).todense()pca=PCA(n_components=2).fit(X_visualise)data2D=pca.transform(X_visualise)plt.scatter(data2D[:,0],data2D[:,1],c=newsgroups_train.target)简单浏览上述代码 。 首先还是加载数据集 , 但只加载了两个类别(我们希望可视化的类别) 。 在此基础上运行计数矢量化和TF-IDF变换 , 并拟合了只需要两个关键分量的PCA模型 。 绘制出效果图后可以清晰地看到数据集中聚类的分离情况如图10.1所示 。
图10.1中的两个坐标轴分别代表PCA转换后的两个关键分量 。
再来回顾原始向量X , 用它来实现聚类 。 在讨论主题模型的章节 , 我们探讨过一些降维技术 , 比如SVD和LSA/LSI(读者可以回顾第8章) , 本例将使用这些技术进行降维 。
对数据集执行SVD操作之后还需要进行归一化处理 。
fromsklearn.decompositionimportTruncatedSVDfromsklearn.preprocessingimportNormalizern_components=5svd=TruncatedSVD(n_components)normalizer=Normalizer(copy=False)lsa=make_pipeline(svd,normalizer)X=lsa.fit_transform(X)经过清洗、TF-IDF转换、降维这3个操作之后 , 最后生成的X向量才是我们需要的输入 , 下一步就可以开始进行聚类处理了 。
10.3K-meansK-means是一种经典的聚类学习算法 , 其原理很容易理解 。 它会根据用户设置的聚类数量 , 通过减少聚类中心点和类中其他各点的距离来达到聚类效果 。 作为一种迭代算法 , 它会一直执行这个过程 , 直到聚类中心点稳定不变 。 我们需要简单地了解这个算法背后的原理 。
用scikit-learn实现K-means非常简单 , scikit-learn库提供了两种实现方式 , 一种是标准K-means , 另一种是小批量K-means 。 下面的代码中包括两种实现 , 用户可自由切换:
minibatch=Trueifminibatch:km=MiniBatchKMeans(n_clusters=true_k,init='k-means++',n_init=1,init_size=1000,batch_size=1000)else:km=KMeans(n_clusters=true_k,init='k-means++',max_iter=100,n_init=1)km.fit(X)通过执行fit函数 , 我们训练出了4个不同的聚类 。 之前我们可视化了聚类结果 , 这里只把每个类别的主题词打印出来:
original_space_centroids=svd.inverse_transform(km.cluster_centers_)order_centroids=original_space_centroids.argsort()[:,::-1]代码中最前面的代码位必须保留 , 因为LSI转换需要用到它 。
terms=vectorizer.get_feature_names()foriinrange(true_k):print("Cluster%d:"%i)forindinorder_centroids[i,:10]:print('%s'%terms[ind])Cluster0:graphicsspaceimagecomuniversitynasaimagesacprogrampostingCluster1:godpeoplecomjesusdonsaybelievethinkbiblejustCluster2:spacehenrytorontonasaaccesscomdigexpatgovalaskaCluster3:sgiliveseykeithsolntzewpdjoncomcaltechmoralitymoral每次训练的结果可能会有差异 , 因为机器学习算法不会每次生成完全相同的结果 。
我们可以看到每个聚类都代表了最初选择的4个类别 , 聚类结果不错 。 我们可以进一步使用训练好的模型来预测新文档属于哪个聚类 , 只需保证预测前对新文档进行了相同的预处理步骤 。
km.predict(X_test)重新回顾聚类的步骤:先加载数据集 , 然后选择4个类别 , 运行预处理步骤 , 可视化数据 , 训练一个K-means模型 , 并为每个聚类打印出最重要的单词以查看它们是否有意义 , 得到了不错的效果 。 因为我们制定了分类数量 , 所以K-means中的K=4 。
接下来读者可以尝试不同的预处理步骤 , 得到不同的聚类效果 。 下面探讨另一种聚类形式 。
10.4层次聚类在介绍层次聚类之前 , 建议先学习scikit-learn中的聚类教程 。 在scikit-learn中切换使用不同的模型是很简单的事情 , 而且聚类过程中的其他步骤始终保持不变 。
我们将使用Ward算法尝试分层聚类 。 该算法基于减少每个聚类内部方差的思想 , 并采用距离度量来实现 。 Ward方法是各种层次聚类算法中最早使用的方法之一 , 它的核心思想是构建聚类并将其按层次排列 。 本例将使用树形图来表示层次聚类 。
使用数据集之前 , 先通过scikit-learn创建一个由成对距离组成的矩阵:
fromsklearn.metrics.pairwiseimportcosine_similaritydist=1-cosine_similarity(X)建立好距离矩阵之后 , 我们将开始调用SciPy库里的ward和dendrogram函数:
fromscipy.cluster.hierarchyimportward,dendrogramlinkage_matrix=ward(dist)fig,ax=plt.subplots(figsize=(10,15))#setsizeax=dendrogram(linkage_matrix,orientation="right")SciPy封装了所有复杂步骤 , 并向我们展示了一个漂亮的图表(见图10.2) 。 树形图提出了一个概念 , 即文档是可以排列的 。 图中x轴代表文档的名称或索引 , 因为文档太多 , 现在无法通过图表看到这些名称或索引 。 y轴指的是聚类的每个层次结构之间的距离 。
因为文档数量的关系 , 我们很难判定图中的聚类结果是否最优 , 也无法了解文档和聚类之间的关系 , 因此可以使用较小的语料库进一步确认效果 。
这里再次强调 , 在将语料库输入到聚类算法之前 , 读者可以尝试使用不同的降维和向量表示方法 。 Word2Vec和Doc2Vec都提供了非常有趣的方法来实现这一点 , Gensim也能够为此提供支持 。
下面介绍文本分类算法 , 这是文本机器学习算法中的另一重要领域 。
10.5文本分类上一节讨论了聚类 , 它是一种无监督的学习算法 。 而分类则是一种有监督的学习算法 。 有监督和无监督分别是什么意思?在前面的示例中 , 有些样本带有标签数据 , 用于表示当前文档实际属于哪个类的信息 。 但你也许会注意到我们从未使用过这些信息 。 当我们训练聚类模型时 , 从不使用标签 。 这种学习称为无监督学习 , 聚类是无监督学习任务的一个常见例子 。
在分类问题中 , 我们知道要将文档或数据点分配给哪些类 , 并使用这些信息来训练我们的模型 。 事实上 , 我们的聚类和分类方法几乎没有任何区别 , 除了注意标签外 , 我们只是使用不同的机器或模型进行训练 。
在开始将文本输入任何机器学习流程之前 , 我们需要确保文本清洗和向量化步骤已经完成 。 虽然没有引入新的步骤 , 但开发人员可以进行适当的调整来提高模型准确性或性能 。
我们将使用NaiveBayes分类器和支持向量机分类器来辅助完成分类任务 。 这些模型的数学性质超出了本书的描述范围 , 有兴趣的读者可以参考阅读scikit-learn的学习文档 。
SVM通过核函数把输入空间映射到另一个空间上 , 以便我们在该空间画出一条线(或者是一个超平面)用于分类 , 如图10.3所示 。 核函数由数学函数组成 , 用于完成向量转换 。
NaiveBayes分类器是通过应用贝叶斯定理来工作的 , 它假定每个特征之间都是独立的 , 我们可以预测文档可能属于哪个类别 。 必须注意的是这种独立性通常是假定的 。 如果这种情况不成立 , 就称为naive 。 使用标签计算文档是否属于某个类的先验概率 。 从本质上讲 , 我们试图找出哪些单词可以用于预测类别 。 代码本身非常简单 , 唯一的区别是我们使用标签来训练模型 。 这里只列出部分代码片段 , 如果想获得完整可运行的代码请参考JupyterNotebook 。 在训练模型之前不要忘记转换数据 , 如果是稀疏数组 , 请先运行X=X.to_array():
fromsklearn.naive_bayesimportGaussianNBgnb=GaussianNB()gnb.fit(X,labels)fromsklearn.svmimportSVCsvm=SVC()svm.fit(X,labels)训练好的gnb和svm模型通过调用predict()方法来预测未知文档的类别 。
NaiveBayes的预测代码如下所示:
gnb.predict(X_test)输出结果是类别数据 , 如果数据集包含4个类别 , 则输出结果如下:
array([0,3,3,...,3,3,3])与SVM类似 , 运行以下代码:
svm.predict(X_test)结果如下:
array([0,3,3,...,3,3,3])虽然聚类是一个更具解释性的过程 , 但在分类过程中 , 我们往往希望提高预测正确类的准确性或成功率 。 GridSearchCV是一个scikit-learn函数 , 它允许我们为分类器对象选择最佳参数 , 并且可以使用classificaiton_report对象检查分类器的性能 。
scikit-learn官方文档给出如下示例:
fromsklearnimportsvm,datasetsfromsklearn.model_selectionimportGridSearchCViris=datasets.load_iris()parameters={'kernel':('linear','rbf'),'C':[1,10]}svc=svm.SVC()clf=GridSearchCV(svc,parameters)clf.fit(iris.data,iris.target)在本例中 , 我们分别对核函数是linear和rbf的SVM进行了参数寻优 , C值分别是1和10 。
另一段官网的代码则可以用多个分类器运行同一个数据集 , 并比较分类器结果的差异 。 图10.4是这些分类器训练和预测时间的比较 。
对于想使用更强大的机器学习工具的读者来说 , 可以参考相关资料来了解如何使用Word2Vec对文档进行分类 。 第12章将详细介绍这部分内容 。
10.6总结总而言之 , 读者现在可以创建自己的分类程序 , 比如将电子邮件分类为垃圾邮件和正常邮件 。 我们已经学习了各种聚类算法 , 如K-means和层次聚类算法 , 也讨论了什么是有监督和无监督的学习算法 , 并学习了如何使用scikit-learn运行这两种算法的示例 。
【文本大数据时代,每个开发人员都需要了解如何分析文本】此外 , 我们还可以使用书中提供的聚类和主题建模工具 , 以各种方式探索文本数据 。 下一章将尝试构建一个简单的信息检索系统来查找相似文档 。


    推荐阅读