【Python机器学习】NLP词频背后的含义——隐性狄利克雷分布(LDiA)

news2024/9/28 3:20:13

目录

LDiA思想

基于LDiA主题模型的短消息语义分析

LDiA+LDA=垃圾消息过滤器

更公平的对比:32个LDiA主题


对于大多数主题建模、语义搜索或基于内容的推荐引擎来说,LSA应该是首选方法。它的数学机理直观、有效,它会产生一个线性变换,可以应用于新来的自然语言文本而不需要训练过程,并几乎不会损失精确率。但是,在某些情况下,LDiA可以给出稍好的结果。

LDiA和LSA(已经底层的SVD)一样做了很多创建主题建模的工作,但是与LSA不同的是,LDiA假设词频满足狄利克雷分布。相对于LSA的线性数学,LDiA则更精确的给出了将词赋给主题的统计信息。

LDiA创建了一个语义向量空间模型,根据词在同一文档中的共现频率将它们分配给主题,然后,文档的主题混合可以由每个主题中的词的混合结果来确定,而这些词被分配给每个主题中。这使得LDiA主题模型更容易理解,因为分配给主题的词以及分配给文档的主题往往比LSA更有意义。

LDiA假设每篇文档都由某个任意数量的主题混合(线性组合)而成,该数量是在开始训练LDiA模型时选择的。LDiA还假设每个主题都可以用词的分布(词项频率)来表示。文档中每个主题的概率或权重,以及某个词被分配到一个主题的概率,都假定一开始满足狄利克雷概率分布(先验)。这就是该算法得名的来历。

LDiA思想

Blei和Ng通过类似思想实验提出了LDiA思想。他们设想,一台只能掷骰子(生成随机数字)的机器如何能写出语料库中的文档。由于我们仅基于词袋进行统计,因此在编写一篇真正的文档时,他们去掉了词序对文档语义的影响,他们只对词的混合统计数据进行建模,而这些词混合构成了每篇文档的词袋。

他们设想有一台机器,该机器只有两个选择项来开始生成特定文档的词混合结果。他们设想文档生成器会以某种概率分布来随机选择这些词,就像选择骰子的边数然后将骰子的组合情况加在一起创建一个D&D人物卡。我们的“人物卡”只需要骰子的两轮投掷过程。但是骰子本身很大,而且有好几个,关于如何组合它们来为不同的值生成所需的概率,有十分复杂的规则。我们希望词的数量和主题的数量有特定的概率分布,这样它们就可以匹配待分析的真实文档中的词和主题的分布。

骰子的两轮投掷过程分别代表:

  1. 生成文档的词的数量(泊松分布)
  2. 文档中混合的主题的数量(狄利克雷分布)

有了上面两个数值之后,就会遇到较难的部分,也就是要为文档选择词。设想的词袋生成机会在这些主题上迭代,并随机选择适合该主题的词,直到达到文档应该包含的词数量为止。确定这些词对应主题的概率(每个主题的词的适宜度)是比较困难的。但是一旦确定,“机器人”就会从一个词项-主题概率矩阵中查找每个主题的词的概率。

因此,这台机器只需要一个泊松分布的参数来告诉它文档的平均长度有多长,以及另外两个参数来定义设置主题数的狄利克雷分布。然后,文档生成算法需要文档喜欢使用的所有词和主题组成的词项-主题矩阵,并且,它还需要喜欢谈论的一个主题混合。

下面将文档生成问题转回最初的问题,即从现有文档中估算主题和词。我们需要为前两个步骤测算或计算关于词和主题的那些参数。然后需要从一组文档中计算出词项-主题矩阵,这就是LDiA所做的事情。

Blei和Ng意识到,他们可以通过分析语料库中文档的统计数据来确定步骤1和步骤2的参数。例如步骤1,可以计算出语料库中文档的所有词袋中的平均词(或n-gram)数量:

import pandas as pd
from nlpia.data.loaders import get_data
from nltk.tokenize import casual_tokenize
pd.options.display.width=120

sms=get_data('sms-spam')
total_corpus_len=0
for document_text in sms.text:
    total_corpus_len=total_corpus_len+len(casual_tokenize(document_text))
mean_document_len=total_corpus_len/len(sms)
print(round(mean_document_len,2))

还可以通过下面这行代码求解:

print(sum([len(casual_tokenize(t)) for t in sms.text])*1.0/len(sms.text))

大家应该直接从词袋来计算这个统计数据,我们需要确保正在对文档中的已分词和已向量化的词计数,并确保在对独立词项进行计数之前,已应用任一停用词过滤器或其他归一化方法。这样的话,我们的计数就不仅包括词袋向量词汇表中的所有词(正在计数的所有n-gram),而且包括词袋使用的那些词(如非停用词)。LDiA算法也依赖一个词袋向量空间模型。

设定LDiA模型所需要的第二个参数即主题的数量更加棘手。在一组特定的文档中,只有在为这些主题分配了词之后,才能直接得到主题的数量。就像KNN、k均值以及其他的聚类算法一样,我们必须提取设定k的值。我们可以猜测主题的数量(类似于k均值中的k,即簇的数量),然后检查这是否适用于这组文档。一旦设定好LDiA要寻找的主题数量,它就会找到要放入每个主题中的词的混合结果,从而优化其目标函数。

我们可以通过调整这个“超参数”(k,即主题的数量)来对其进行优化,直到它适合我们的应用为止。如果能够度量表示文档含义的LDiA语言模型的质量,就可以自动化上述优化过程。可以用于词优化的一个代价函数是,LDI模型在某些分类或回归问题(如情绪分析、文档关键词标注或主题分析)中的表现如何。我们只需要一些带标签的文档来测试主题模型或分类器。

基于LDiA主题模型的短消息语义分析

LDiA生成的主题对人类来说更容易理解和解释。这是因为经常一起出现的词被分配给相同的主题,而人类的期望也是如此。

这听起来好像是一回事,但事实并非如此。其背后的数学子啊优化不同的东西,优化器有不同的目标函数,因此它将达到一个不同的目标。为了让接近的高维空间向量在低维空间中继续保持接近,LDiA必须以非线性的方式变换(扭转和扭曲)空间(向量)。这种过程很难实现可视化,除非在某个三维空间上执行上述操作并将结果向量投影到二维空间。

以nlpia中的horse为例,我们可以为horse中的数千个点创建词-文档向量,方法是将它们转换为词x、y、z(即三维空间向量的维数)上的整数计数结果。然后,可以从这些计数生成人造文档,并将它们传递给LDiA和LSA示例。然后,我们就可以直接实现上述每一种方法产生马的不同的二维影子(投影)的过程的可视化。

下面来看对于一个包含数千条短消息的数据集(按照是否垃圾来标记)上述方法的应用过程。首先计算TF-IDF向量,然后为每个短消息计算一些主题向量。我们假设只使用16个主题来对垃圾短消息进行分类。保持主题(维度)的数量较低有助于减少过拟合的可能性。

LDiA使用原始词袋词频向量,而不是归一化的TF-IDF向量。这里有一个简单的方法在scikit-learn中计算词袋向量:

from sklearn.feature_extraction.text import CountVectorizer
from nltk.tokenize import casual_tokenize
import numpy as np
import pandas as pd
from nlpia.data.loaders import get_data

sms=get_data('sms-spam')
index=['sms{}{}'.format(i,'!'*j) for (i,j) in zip(range(len(sms)),sms.spam)]
sms.index=index

np.random.seed(42)
counter=CountVectorizer(tokenizer=casual_tokenize)
bow_docs=pd.DataFrame(counter.fit_transform(raw_documents=sms.text).toarray(),index=index)
column_nums,terms=zip(*sorted(zip(counter.vocabulary_.values(),counter.vocabulary_.keys())))
bow_docs.columns=terms

#检查一下,看这里的词频是否对标记为"sms0"的第一条短消息有意义
print(sms.loc['sms0'].text)
print(bow_docs.loc['sms0'][bow_docs.loc['sms0']>0].head())

下面给出了如何使用LDiA为短消息语料库创建主题向量的过程:

from sklearn.decomposition import LatentDirichletAllocation as LDiA
ldia=LDiA(n_components=16,learning_method='batch')
ldia=ldia.fit(bow_docs)
print(ldia.components_.shape)

因此,上述模型已经将9232个词(词项)分配给16个主题(成分)。下面看开头的几个词,了解一下它们是如何分配到16个主题的。LDiA是一种随机算法,它依赖随机数生成器做出一些统计决策来为主题分配词,所以每次运行sklearn.LatentDirichletAllocation,如果随机种子没有设定为固定值,都将获得不一样的结果:

pd.set_option('display.width',75)
components=pd.DataFrame(ldia.components_.T,index=terms,columns=columns)
print(components.round(2).head(3))

因此,感叹号(!)被分配到大多数主题中,但它其实是topic3的特别重要的部分,在该主题中,引号几乎不起作用。或许topic3关注情感的强度或强调,并不太在意数值或引用。

print(components.topic3.sort_calues(ascending=False)[:10])

可以看到,该主题的前10个词似乎是在要求某人做某事或支付某事的强调指令中可能使用的词类型。如果该主题更多使用在垃圾信息而不是非垃圾信息的话,那么这个发现很特别哦我们可以看到,即使这样粗略浏览一下,也可以对主题的词分配进行合理化解释或推理。

在拟合LDA分类器之前,需要为所有文档(短消息)计算出LDiA主题向量。下面看一下这些向量与SVD及PCA为相同文档生成的主题向量的不同:

ldia16_topic_vectors=ldia.transform(bow_docs)
ldia16_topic_vectors=pd.DataFrame(ldia16_topic_vectors,index=index,columns=columns)
print(ldia16_topic_vectors.round(2).head())

可以看到,上述主题之间分隔得更清晰,在为消息分配主题时,会出现很多0。在基于NLP流水线结果做出业务决策时,这是使LDiA主题更容易向同伴解释的做法之一。

LDiA+LDA=垃圾消息过滤器

下面观察这些LDiA主题在预测时的有效性,再次使用LDiA主题向量来训练LDA模型:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.model_selection import train_test_split
X_train,X_text,y_train,y_test=train_test_split(ldia16_topic_vectors,sms.spam,test_size=0.5,random_state=271828)
lda=LDA(n_components=1)
lda=lda.fit(X_train,y_train)
sms['ldia16_spam']=lda.predict(ldia16_topic_vectors)
print(round(float(lda.score(X_text,y_test)),2))

train_test_split和LDiA的算法是随机的,所以如果不设置特定种子,每次运行会得到不同的结果和不同的精确率。

共线警告可能发生的一种情况是:如果文本包含一些2-gram或3-gram,其中组成他们的词只出现在这些2-gram或3-gram中。因此,最终的LDiA模型必须在这些相等的词项频率之间任意分配权重。当在短消息中导致共线性的词出现时,另一个词(它的配对)总是在相同的消息中。

我们可以使用Python而不是手工进行搜索。首先,我们可能只想在语料库中寻找任何相同的词袋向量。这些向量可能出现在不完全相同的短消息中,因为它们有相同的出现频率。我们可以遍历所有词袋对,以寻找相同的向量。这些向量肯定会在LDiA或LSA中引发共线警告。

如果没有找到任何词袋向量的精确副本,那么可能遍历词汇表中所有的词对。然后遍历所有的词袋,以寻找包含完全相同的词对的短消息。如果这些词在短消息中没有单独出现过,那么已经在数据集中找到了一个“共线”。一些常见的2-gram(比如英文人名)可能会导致这种情况,而且从来没有分开使用过,例如“Bill Gates”。

我们在测试集上获得的精确率超过90%,而且只需要在一半的可用数据上进行训练。但是,由于数据集有限,我们确实得到了关于特征共线的警告,这给LDA带来了一个待确定问题。一旦使用train_test_split丢弃了一半的文档,那么主题-文档矩阵的行列式就接近于零。如果需要的话,可以关闭LDiA n_components来解决这个问题,但是它往往会将这些主题组合在一起,而这些主题是彼此的线性组合(共线)。

但是,我们看一下这里的LDiA模型与基于TF-IDF向量的高维模型相比如何。TF-IDF向量有更多的特征(超过3000个独立的词项),所以很可能会遇到过拟合和弱泛化问题,这就是LDiA和PCA泛化的用武之地:

from nlpia.data.loaders import get_data

sms=get_data('sms-spam')
index=['sms{}{}'.format(i,'!'*j) for (i,j) in zip(range(len(sms)),sms.spam)]
sms.index=index


from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize.casual import casual_tokenize
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.model_selection import train_test_split
tfidf=TfidfVectorizer(tokenizer=casual_tokenize)
tfidf_docs=tfidf.fit_transform(raw_documents=sms.text).toarray()
tfidf_docs=tfidf_docs-tfidf_docs.mean(axis=0)
X_train,X_text,y_train,y_test=train_test_split(tfidf_docs,sms.spam.values,test_size=0.5,random_state=271828)
lda=LDA(n_components=1)
lda=lda.fit(X_train,y_train)
print(round(float(lda.score(X_train,y_train)),3))
print(round(float(lda.score(X_text,y_test)),3))

在训练集上基于TF-IDF的模型的精确率是完美的,但是,当使用低维主题向量而不是TF-IDF向量训练时,测试集上的精确率要低很多。

测试集的精确率是唯一重要的精确率。这正是主题建模(LSA)应该做的,它可以帮助我们从一个小型训练集中泛化出模型,因此它仍然可以很好地处理使用不同词组合的消息。

更公平的对比:32个LDiA主题

下面使用更多的维度和更多的主题。也许LDiA不如LSA(PCA)高效,所以它需要更多的主题来分配词,比如32个主题(成分):

from nlpia.data.loaders import get_data
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize.casual import casual_tokenize
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.model_selection import train_test_split
from sklearn.decomposition import LatentDirichletAllocation as LDiA
from sklearn.feature_extraction.text import CountVectorizer
from nltk.tokenize import casual_tokenize
import numpy as np
import pandas as pd

sms=get_data('sms-spam')
index=['sms{}{}'.format(i,'!'*j) for (i,j) in zip(range(len(sms)),sms.spam)]
sms.index=index

np.random.seed(42)
counter=CountVectorizer(tokenizer=casual_tokenize)
bow_docs=pd.DataFrame(counter.fit_transform(raw_documents=sms.text).toarray(),index=index)
column_nums,terms=zip(*sorted(zip(counter.vocabulary_.values(),counter.vocabulary_.keys())))
bow_docs.columns=terms

ldia32=LDiA(n_components=32,learning_method='batch')
ldia32=ldia32.fit(bow_docs)
print(ldia32.components_.shape)

下面计算所有文档(短消息)的新的32维主题向量:

ldia32_topic_vectors=ldia32.transform(bow_docs)
columns32=['topic{}'.format(i) for i in range(ldia32.n_components)]
ldia32_topic_vectors=pd.DataFrame(ldia32_topic_vectors,index=index,columns=columns32)
print(ldia32_topic_vectors.round(2).head())

我们可以看到在,这些主题更加稀疏,而且能够更加清晰的分开。

下面是LDA模型(分类器)的训练过程,这次使用32维的LDiA主题向量:

X_train,X_text,y_train,y_test=train_test_split(ldia32_topic_vectors,sms.spam.values,test_size=0.5,random_state=271828)
lda=LDA(n_components=1)
lda=lda.fit(X_train,y_train)
sms['ldia32_spam']=lda.predict(ldia32_topic_vectors)
print(X_train.shape)
print(round(float(lda.score(X_train,y_train)),3))
print(round(float(lda.score(X_text,y_test)),3))

不要将这里“主题”或成分数量的优化与前面的共线性问题混淆。增加或减少主体的数量并不能解决或造成共线问题。这是底层数据造成的问题。如果想要摆脱这个警告,那么需要将“噪声”或元数据以人造词的方式添加到短消息中,或者需要删除那些重复的词向量。如果文档中有重复出现多次的词向量或词对,那么主题的数量优化也无法解决这个问题。

主题的数量越多,那么主题的精确率就可以越高,至少对这个数据集来货,产品这一主题线性分隔得更好。但是这里的效果仍然不如PCA+LDA的96%的精确率。因此,PCA能使这里的短消息主题向量更有效的展开,这样就允许时候用超平面以更大的消息间隔来分隔类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2089170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程间通信--IPC机制

今天主要讲述独立的进程之间的通信,我们知道,进程是一个完整代码的执行过程,那么我们想实现在进程运行的过程之中传递信息或者是发送数据,就是通过IPC机制来完成。 一、什么是IPC机制 IPC:inter process communication…

文件泄密?不存在的!一文读懂文件防泄密最新五个小妙招

在当今信息化时代,企业数据的安全性显得尤为重要。文件泄密事件频发,不仅会给企业带来巨大的经济损失,还可能损害企业的声誉。因此,如何有效防止文件泄密成为了企业管理中的重中之重。本文将为大家介绍最新的五个防泄密妙招&#…

vue大数据展示之虚拟列表

面试代码学习 父组件&#xff1a; <template><div class"box"><!--items总条数、 size数据高度、 shownumber每次渲染数据--><list :items"items" :size"60" :shownumber"10"></list></div><…

要实现主动元数据,关键技术在算子级血缘解析

主动元数据管理最早被 Gartner 在 2016 年提出&#xff0c;在 2022 年 Gartner 公布的顶级战略技术趋势中&#xff0c;主动元数据被认为是实现 Data Fabric&#xff08;数据编织&#xff09;和主动数据治理的基石&#xff0c;也是实现 Data Fabric 的关键能力 。在这份技术趋势…

全面解析:动态住宅代理的关键优势

在大数据时代的背景下&#xff0c;代理IP成为了很多企业顺利开展的重要工具。代理IP地址可以分为住宅代理IP地址和数据中心代理IP地址。选择住宅代理IP的好处是可以实现真正的高匿名性&#xff0c;而使用数据中心代理IP可能会暴露自己使用代理的情况。 住宅代理IP是指互联网服务…

关于springboot的Rest请求映射处理的源码分析(二)

前面我们知道了他怎么处理表单映射&#xff0c;这里我们来研究一下&#xff0c;他是如何处理具体请求的。也就是说我有那么多/user你是怎么定位到我在哪个cotroller&#xff0c;并且你是怎么定位到我具体是哪个接口。 这里我们就来逐步定位一下这个问题。 一、组件分析 老路子…

Nacos 部分漏洞整理

免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. Naco简介 微信公众号搜索:南风漏洞复现文库 该文…

element中 el-input 不更新的问题

需要在上面输入数字,下面一列都更改成一样的数字 batchChange(list,field,value){console.log(list,field,value);list.forEach((i,index) > {i[field]value;this.$set(list,index, JSON.parse(JSON.stringify(i)));});} 用 JSON.parse(JSON.stringify(i)) 转一下后,就可以…

langchain入门系列之八 langgraph多agent示例

在之前的文章中我们介绍了langgraph&#xff0c;并且用它做了一个小小的示例&#xff0c;在本文中&#xff0c;我们将使用智普清言来构建多agent 系统。百度千帆对langgraph支持较差(尤其是强制要求奇数偶数的role设置&#xff0c;传入messages的奇数偶数要求&#xff0c;让人有…

用好外呼机器人,帮助企业提升客户管理效率

外呼机器人&#xff0c;作为现代科技与企业管理的结合体&#xff0c;正在企业客户管理领域掀起革命性的变化。随着人工智能技术的不断进步&#xff0c;外呼机器人不仅实现了自动化呼叫&#xff0c;还能根据客户的语音情感进行相应的反馈和操作&#xff0c;极大地提高了客户满意…

AI大模型编写多线程并发框架(六十三):监听器优化·上

系列文章目录 文章目录 系列文章目录前言一、项目背景二、第七轮对话-补充异步执行代码三、第八轮对话-增加累计完成等字眼四、第九轮对话-线程安全优化五、第十轮对话-增加运行时数据七、参考文章 前言 在这个充满技术创新的时代&#xff0c;AI大模型正成为开发者们的新宠。它…

SpringBoot+Vue的图书管理系统【包含运行步骤】

SpringBootVue图书管理系统 一、项目介绍1. 图书信息管理2. 图书类型管理3. 图书借阅管理4. 用户管理 二、技术选型后端技术选型前端技术选型 三、运行步骤后端启动前端启动 四、项目演示源码获取方式 五、总结与展望 大家好&#xff0c;这里是程序猿代码之路&#xff01;随着信…

Linux基础1-基本指令7(其他常用指令,shell简介)

目录 1.uname 2.常用小指令 3.查看系统信息的其他指令 4.shell命令及其原理 4.1这里我们简单了解一下shell 4.2 shell存在的意义&#xff1f; 1.uname 如何查看计算机体系架构&#xff1f; uname -a,查看详细信息 uname -r 查看简要信息 2.常用小指令 TAB&#x…

Socket编程---UDP篇

目录 一. UDP协议 二. Socket编程 2.1 sockaddr家族 2.2 接口介绍 三. 服务端实现 四. 服务端调用实现 五. 客户端实现 六. 效果展示 一. UDP协议 何为UDP协议的含义&#xff0c;上篇粗略提及了一下TCP与UDP的区别&#xff1a; TCP&#xff1a; •…

将军百战死,程序十年成

将军百战死&#xff0c;程序十年成 十年前的 2014.8.3 我释出了动词算子式通用代码生成器的第一个完整版本 InfinityGPGenerator 0.6.5&#xff0c;即无垠式通用代码生成器 0.6.5。这是一个重大的里程碑。十年后&#xff0c;通用代码生成器已经是一个大家族。昨天&#xff0c;…

插入排序的动画展示与实现

排序学习思路&#xff1a;先实现单趟逻辑&#xff0c;在实现整体逻辑&#xff1b;先解决普遍情况&#xff0c;再解决特殊情况。 什么是插入排序 回忆下自己玩扑克牌的时候是怎么把手上的牌理顺的吧&#xff01;其实那就是插入排序&#xff0c;从左边往右边&#xff0c;把一张张…

强烈推荐!大模型辅助软件开发

图书推荐 作者介绍 很喜欢作者在书上的这句话了&#xff1a;是人类工程师的能力&#xff0c;而不是大模型的能力&#xff0c;决定了大模型协作式开发的上限。 本书内容 软件开发正在经历一场前所未有的范式变革。人工智能的飞速发展&#xff0c;特别是大型语言模型所取得的成…

【Python篇】Python 类和对象:详细讲解(上篇)

文章目录 Python 类和对象&#xff1a;详细讲解1. 什么是类&#xff08;Class&#xff09;类的定义 2. 什么是对象&#xff08;Object&#xff09;创建对象 3. 属性和方法属性&#xff08;Attributes&#xff09;方法&#xff08;Methods&#xff09;在类中定义属性和方法使用对…

使用facebook开源prophet模型预测上证指数etf股价

可以图个乐&#xff0c;没有那么准确&#xff0c;可能还需要更深入的研究分析 蓝线是预测的2024年的走势&#xff0c;绿线是实际走势&#xff0c;红线是历史和未来的分界线。结果上有蛮多差异的。 # 测试预测2024年 coded by luke 伊玛目的门徒 import akshare as ak impor…

基于Java的心灵治愈交流平台

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java语言&#xff1b;Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat 系统展示 首页 心…