【Python机器学习】NLP词中的数学——主题建模

news2025/2/24 20:40:57

目录

齐普夫定律

相关度排序

工具

其他工具

Okapi BM25


在文档向量中,词计数是有用的,但是纯词计数,即使按照文档长度进行归一化处理,也不能告诉我们太多该词在当前文档相对于语料库中其他文档的重要度信息。如果能弄清楚这些信息,我们就能开始描述语料库中的文档了。假设我们有一个收集了所有风筝数据的语料库,那么几乎可以肯定的是“Kite”一词会在每一个文档中出现很多次,但这不能提供任何新信息,对区分文档没有任何帮助。像“construction”这样的词可能不会在整个语料库中普遍出现,但是对于这些词频繁出现的那些文档,我们会对每篇文档的本质有更多了解。为此,我们需要另一个工具。

逆文档频率(IDF),在齐普夫定律下为主题分析打开了一扇新窗户。我们从前面的词项频繁计数器开始,然后对它进行扩展。我们可以通过两种方式对词条计数并对它们装箱处理:对每篇文档进行处理或遍历整个语料库。

下面我们只按文档计数:

from nltk.tokenize import TreebankWordTokenizer
tokenizer=TreebankWordTokenizer()

kite_txt_1="""
A kite is traditionally a tethered heavier-than-air craft with wing surfaces that react against the air to create lift and drag. A kite consists of wings, tethers, and anchors. Kites often have a bridle to guide the face of the kite at the correct angle so the wind can lift it. A kite’s wing also may be so designed so a bridle is not needed; when kiting a sailplane for launch, the tether meets the wing at a single point. A kite may have fixed or moving anchors. Untraditionally in technical kiting, a kite consists of tether-set-coupled wing sets; even in technical kiting, though, a wing in the system is still often called the kite.
The lift that sustains the kite in flight is generated when air flows around the kite’s surface, producing low pressure above and high pressure below the wings. The interaction with the wind also generates horizontal drag along the direction of the wind. The resultant force vector from the lift and drag force components is opposed by the tension of one or more of the lines or tethers to which the kite is attached. The anchor point of the kite line may be static or moving (such as the towing of a kite by a running person, boat, free-falling anchors as in paragliders and fugitive parakites or vehicle).
The same principles of fluid flow apply in liquids and kites are also used under water. A hybrid tethered craft comprising both a lighter-than-air balloon as well as a kite lifting surface is called a kytoon.
Kites have a long and varied history and many different types are flown individually and at festivals worldwide. Kites may be flown for recreation, art or other practical uses. Sport kites can be flown in aerial ballet, sometimes as part of a competition. Power kites are multi-line steerable kites designed to generate large forces which can be used to power activities such as kite surfing, kite landboarding, kite fishing, kite buggying and a new trend snow kiting. Even Man-lifting kites have been made.
"""
kite_txt_2="""
Kites were invented in China, where materials ideal for kite building were readily available: silk fabric for sail material; fine, high-tensile-strength silk for flying line; and resilient bamboo for a strong, lightweight framework.
The kite has been claimed as the invention of the 5th-century BC Chinese philosophers Mozi (also Mo Di) and Lu Ban (also Gongshu Ban). By 549 AD paper kites were certainly being flown, as it was recorded that in that year a paper kite was used as a message for a rescue mission. Ancient and medieval Chinese sources describe kites being used for measuring distances, testing the wind, lifting men, signaling, and communication for military operations. The earliest known Chinese kites were flat (not bowed) and often rectangular. Later, tailless kites incorporated a stabilizing bowline. Kites were decorated with mythological motifs and legendary figures; some were fitted with strings and whistles to make musical sounds while flying. From China, kites were introduced to Cambodia, Thailand, India, Japan, Korea and the western world.
After its introduction into India, the kite further evolved into the fighter kite, known as the patang in India, where thousands are flown every year on festivals such as Makar Sankranti.
Kites were known throughout Polynesia, as far as New Zealand, with the assumption being that the knowledge diffused from China along with the people. Anthropomorphic kites made from cloth and wood were used in religious ceremonies to send prayers to the gods. Polynesian kite traditions are used by anthropologists get an idea of early "primitive" Asian traditions that are believed to have at one time existed in Asia.
"""
kite_intro=kite_txt_1.lower()
intro_tokens=tokenizer.tokenize(kite_intro)
kite_history=kite_txt_2.lower()
history_tokens=tokenizer.tokenize(kite_history)
intro_total=len(intro_tokens)
print(intro_total)
history_total=len(history_tokens)
print(history_total)

现在,由两篇分词后的kite文档,我们计算“kite”在每篇文档中的词项频率。我们将词项频率存储到两个字典中,其中每个字典对应一篇文档。

from collections import Counter
intro_tf={}
history_tf={}
intro_counts=Counter(intro_tokens)
intro_tf['kite']=intro_counts['kite']/intro_total
history_counts=Counter(history_tokens)
history_tf['kite']=history_counts['kite']/history_total
print(intro_tf['kite'],history_tf['kite'])

可以看到,“kite”在两篇文档中的词项频率分别是0.0388和0.0202。

进一步挖掘,看下其他词的词项频率数字:

intro_tf['and']=intro_counts['and']/intro_total
history_tf['and']=history_counts['and']/history_total
print(intro_tf['and'],history_tf['and'])

可以看到,这两篇文档和“and”的相关度,与它们和“kite”的相关度相差不大。这似乎没什么用。

考虑词项逆文档频率的一个好方法是:这个词条在此文档中有多稀缺?如果一个词项在某篇文档中出现很多次,但很少出现在语料库的其他文档中,那么就可以假设它对当前文档非常重要。

词项的IDF仅仅是文档总数与该词项出现的文档数之比。在当前示例中的“and”和“kite”,它们的IDF是相同的:

  • 文档总数/出现“and”的文档数=2/2=1
  • 文档总数/出现“kite”的文档数=2/2=1
  • 文档总数/出现“China”的文档数=2/1=2

出现了一个不同的结果,下面使用这种稀缺度指标来对词项频率加权:

num_docs_containing_and=0
for doc in [intro_tokens,history_tokens]:
    if 'and' in doc:
        num_docs_containing_and=num_docs_containing_and+1

获取“China”在两篇文档中的词项频率值:

intro_tf['China']=intro_counts['China']/intro_total
history_tf['China']=history_counts['China']/history_total

最后,计算3个词的IDF。我们就像存储词项频率一样把IDF存储在每篇文档的字典中:

num_docs=2
intro_ifd={}
history_idf={}
intro_ifd['and']=num_docs/num_docs_containing_and
history_idf['and']=num_docs/num_docs_containing_and
intro_ifd['kite']=num_docs/num_docs_containing_and
history_idf['kite']=num_docs/num_docs_containing_and
intro_ifd['china']=num_docs/num_docs_containing_and
history_idf['china']=num_docs/num_docs_containing_and

然后对文档intro和文档history有:

intro_tfidf={}
intro_tfidf['and']=intro_tf['and']*intro_ifd['and']
intro_tfidf['kite']=intro_tf['kite']*intro_ifd['kite']
intro_tfidf['china']=intro_tf['china']*intro_ifd['china']
history_tfidf={}
history_tfidf['and']=history_tf['and']*history_idf['and']
history_tfidf['kite']=history_tf['kite']*history_idf['kite']
history_tfidf['china']=history_tf['china']*history_idf['china']

齐普夫定律

假设我们拥有一个包含100万篇文档的语料库,有人搜索“cat”这个词,在上述100万篇文档中,只有一篇文档包含“cat”。那么这个词的原始或源生IDF为:

1000000/1=1000000

假设有10篇文章包含“dog”,那么“dog”的IDF为:

1000000/10=100000

上述两个结果显著不同。齐普夫会说上面的差距太大了,因为这种差距可能会经常出现。齐普夫定律表明,当比较两个词的词频时,即使它们出现的次数类似,更频繁出现的词的词频也将指数级地高于较不频繁出现的词的词频。因此,齐普夫定律建议使用对数log()来对词频(和文档频率)进行尺度的缩放处理。这就能够确保像“cat”和“dog”这样的词,即使它们出现的次数类似,在最后的词频计算结果上也不会出现指数级的差异。此外,这种词频的分布将确保TF-IDF分数更加符合均匀分布。因此,我们应该将IDF重新定义为词出现在某篇文档中原始概率的对数。对于词项频率,我们也会进行对数处理。

对数函数的底并不重要,因为我们只想使频率分布均匀,而不是将值限定在特定的数值范围内进行缩放。如果用一个以10为底的对数函数,我们会得到:

search:cat——idf=lg(1000000/1)=6

search:dog——idf=lg(1000000/10)=5

所以现在要根据它们在语言中总体出现的次数,对每一个TF结果进行适当的加权。

最终,对于语料库D中给定的文档d里的词项t,有:

tf(t,d)=(t在d中出现的次数)/(d的长度)

tf(t,D)=lg(文档数/包含t的文档数)

tfidf(t,d,D)=tf(t,d)*idf(t,D)

因此,一个词在文档中出现的次数越多,它在文档中的TF(进而TF-IDF)就会越高。与此同时,随着包含该词的文档数增加,该词的IDF(进而TF-IDF)将下降。现在,我们有了一个计算机可以处理的数字,它将特定词或词条与特定语料库中的特定文档关联起来,然后根据该词在整个语料库中的使用情况,为该词在给定文档中的重要度赋予了一个数值。

在一些情况下,所有的计算可以都在对数空间中进行,这样乘法就变成了加法,处罚就变成了减法:

log_tf=log(term_occurences_in_doc)-log(num_terms_in_doc)
log_idf=log(log(total_num_docs))-log(num_docs_containing_term)
log_tf_idf=log_tf+log_idf

TF-IDF这个独立的数字,是简单搜索引擎的简陋的基础。线性代数对于全民理解自然语言处理中使用的工具并不是必需的,但是大体上熟悉公式的工作原理可以使它们的使用更加直观。

相关度排序

我们可以很容易地比较两个向量来得到它们的相似度,然而我们已经了解到,仅仅对词计数并不像使用它们的TF-IDF那样具有可描述性。因此,在每个文档向量中,我们用词的TF-IDF替换TF。现在,向量将更全面地反映文档的含义或主题,像是下面的case:

import copy
from nltk.tokenize import TreebankWordTokenizer
tokenizer=TreebankWordTokenizer()
from collections import Counter
from collections import OrderedDict

docs=["""
The faster Harry got to the store, the faster and faster Harry would get home.
"""]
docs.append("""
Harry is hairy and faster than Jill
""")
docs.append("""
Jill is not as hairy as Harry
""")
doc_tokens=[]
for doc in docs:
    doc_tokens=doc_tokens+[sorted(tokenizer.tokenize(doc.lower()))]
all_doc_tokens=sum(doc_tokens,[])
lexicon=sorted(set(all_doc_tokens))
zero_vector=OrderedDict((token,0) for token in lexicon)


document_tfidf_vectors=[]
for doc in docs:
    vec=copy.copy(zero_vector)
    tokens=tokenizer.tokenize(doc.lower())
    token_counts=Counter(tokens)
    for key,value in token_counts.items():
        docs_containing_key=0
        for _doc in docs:
            if key in _doc:
                docs_containing_key=docs_containing_key+1
        tf=value/len(lexicon)
        if docs_containing_key:
            idf=len(docs)/docs_containing_key
        else:
            idf=0
        vec[key]=tf*idf
    document_tfidf_vectors.append(vec)
print(document_tfidf_vectors)

在上述设置下,我们就得到了语料库中每篇文档的K维向量表示。在给定的向量空间中,如果两个向量有相似的角度,可以说它们是相似的。

如果两个向量的余弦相似度很高,那么它们就被认为是相似的。因此,如果最小化余弦相似度,就可以找到两个相似的向量:

cos\Theta =\frac{A\cdot B}{\left | A \right |\left | B \right |}

现在,我们已经有了进行基本TF-IDF搜索的所有东西,我们可以将搜索查询本身视为文档,从而获得它的基于TF-IDF的向量表示,最后一步是找到与查询余弦相似度最高的向量的文档,并将这些文档作为搜索结果返回。

下面是一个简单的case:

query="How long does it take to get to the store?"
query_vec=copy.copy(zero_vector)
tokens=tokenizer.tokenize(query.lower())
token_counts=Counter(tokens)
for key,value in token_counts.items():
    docs_containing_key=0
    for _doc in docs:
        if key in _doc.lower():
            docs_containing_key=docs_containing_key+1
        if docs_containing_key==0:
            continue
        tf=value/len(tokens)
        idf=len(docs)/docs_containing_key
        query_vec[key]=tf*idf
print(cosine_sim(query_vec,document_tfidf_vectors[0]))
print(cosine_sim(query_vec,document_tfidf_vectors[1]))
print(cosine_sim(query_vec,document_tfidf_vectors[2]))

可以看到,对于当前查询,文档0的相关度最高。通过这种方式我们可以在任何语料库中寻找相关的文档,无论是维基百科的文章还是来自推特的推文。

对于每个查询而言,都必须对所有TF-IDF向量进行“索引扫描”。这是一个复杂度为O(N)的算法。由于使用了倒排索引,大多数搜索引擎可以在常数时间(O(1))内响应。

关键词搜索只是NLP流水线中的一个工具,而我们的目标是构建一个聊天机器人,大多数聊天机器人高度依赖搜索引擎。并且,一些聊天机器人完全依赖搜索引擎,将它作为生成回复的唯一算法。我们需要采用额外的步骤将简单搜索索引(TF-IDF)转换为聊天机器人。我们需要将“问题-回复”对形式的训练数据存储起来。然后,就可以使用TF-IDF搜索与用户输入的文本最相似的问题。这里我们不返回数据库中最相似的语句,而是返回与该语句关联的回复。就像任何棘手的计算机科学问题一样,我们的问题可以通过加入一个间接层来解决。

工具

很久以前搜索就已经自动化处理,有很多相关的实现代码。我们也可以使用scikit-learn包找到快速路径。

下面使用sklearn来构建TF-IDF矩阵。sklearn TF-IDF类是一个包含.fit()和.transform()方法的模型,这些方法遵循所有机器学习模型的sklearn API:

from sklearn.feature_extraction.text import TfidfVectorizer

docs=["""
The faster Harry got to the store, the faster and faster Harry would get home.
"""]
docs.append("""
Harry is hairy and faster than Jill
""")
docs.append("""
Jill is not as hairy as Harry
""")

corpus=docs
vectorizer=TfidfVectorizer(min_df=1)
model=vectorizer.fit_transform(corpus)
print(model.todense().round(2))

利用scikit-learn,我们在上面的代码中创建了一个由3行文档组成的矩阵,以及词库中每个词项的逆文档频率。现在有一个表示3个文档的矩阵,词库中每个词项、词条或词的TF-IDF构成矩阵的列。因为分词方式不同,而且去掉了标签符号,所以词库中只有16个词项。对大规模文本而言,这种或其他一些预优化的TF-IDF模型将为我们省去大量工作。

其他工具

TF-IDF矩阵(词项-文档矩阵)一直是信息检索(搜索)的主流。为了提高搜索结果相关性,下面是一些可以归一化和平滑词项频率权重的方案:

方案定义
Nonew_{ij}=f_{if}

TF-IDF

w_{ij}=log(f_{ij})*log(\frac{N}{n_{j}})
TF-ICFw_{ij}=log(f_{ij})*log(\frac{N}{n_{j}})
Okapi BM25w_{ij}=\frac{f_{ij}}{0.5+1.5*\frac{f_{j}}{\frac{f_{j}}{j}}}log\frac{N-n_{j}+0.5}{f_{ij}+0.5}

搜索引擎(信息检索系统)在查询和语料库中的文档之间匹配关键词(词项)。

Okapi BM25

除了计算TF-IDF余弦相似度,还可以对相似度进行归一化和平滑处理。忽略查询文档中词项的重复出现,从而可以有效地将查询向量的词频都简化为1.这里,余弦相似度的点积不是很具TF-IDF向量的模(文档和查询中的词项数)进行归一化,而是由文档长度本身的一个非线性函数进行归一化:

q_idf*dot(q_tf,d_tf[i])*1.5/(dot(q_tf,d_tf[i])+0.25+0.75*d_num_words[i]/d_num_words.mean()))

通过选择给用户提供最相关结果的权重方案,我们可以优化流水线。但是,如果所处理的语料库不是太大,可以考虑继续往下探索,对词和文档的含义进行更有用和更准确的表示。相比于TF-IDF加权、词干还原和词形归并所希望达到的目标,语义搜索会好得多。

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

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

相关文章

carla unreal engine源码:如何创建radar可视化探测锥

文章目录 前言一、C实现方法1、DrawDebugCone函数2、carla工程修改3、make launch4、探测锥验证 二、蓝图实现方法1、创建并打开蓝图2、打开蓝图事件图表3、绘制蓝图事件4、编译再运行 前言 1、在自动驾驶仿真调试以及测试过程中,我们经常会用到雷达的探测锥&#…

SkyWalking部署(监控系统)

简介 SkyWalking 是一个开源的应用性能监控 (APM) 和可观测性平台,旨在帮助开发者、运维人员和架构师监控、诊断和优化微服务架构中的应用。SkyWalking 提供了一套完整的工具链,用于收集、分析和可视化应用的性能指标、追踪和日志数据。 SkyWalking 的…

wpf prism 《2》、导航

》》》主程序 using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using Prism.Navigation.Regions; using System;namespace BlankApp2.ViewModels {public class MainViewModel : BindableBase{private string _title "Prism Application";public…

数据结构《排序》

在之前数据结构之算法复杂度章节中我们学习了复杂度相关的概念,这就使得懂得如何来区分算法的好坏,在之前C语言专题中在指针的学习时我们了解了冒泡排序,之后再数据结构的二叉树章节中我们又学习了堆排序,其实排序不止这两种&…

搜剧平台源码 可一键转存他人链接

简介 1、一键转存他人链接:就是将别人的分享链接转为你自己的 2、转存心悦搜剧资源:就是将心悦搜剧平台上的所有资源都转成你自己的 3、每日自动更新:自动转存每天的资源并入库 前端uin-app,后端PHP,兼容微信小程序…

基于vue框架的博物馆预约网站的设计与实现8k352(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,类别,博物馆,预约信息,馆藏精品 开题报告内容 基于Vue框架的博物馆预约网站的设计与实现开题报告 一、开题报告名称 基于Vue框架的博物馆预约网站的设计与实现 二、研究背景与意义 随着信息技术的飞速发展和人们生活水平的日益…

QT5.14.2编译有界面的DLL供C#Winform程序调用步骤

目标:公司要设计一套软键盘程序给到WinForm程序调用、因此需要封装QT的软键盘程序给到C#调用,跟C#调用MFC的DLL代码差不多,感觉就是封装了一下QT的代码成为MFC格式的。 步骤:1、新建QT对应的库项目、编译器使用MSVC2017 64位、编…

Apache RocketMQ 中文社区全新升级丨阿里云云原生 7 月产品月报

云原生月度动态 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》,从趋势热点、产品新功能、服务客户、开源与开发者动态等方面,为企业提供数字化的路径与指南。 趋势热点 🥇 通义灵码入选 2024 世界人工智能大会最高荣誉「镇…

Beyond Compare忽略特定格式文本,忽略匹配正则表达式

一 概述 文本对比时忽略某些文本。比如有些生成的文件需要做差异对比,除了内容有差异外,自动生成的ID也不同,想忽略这些ID。特别是文件内容比较多的时候。 如上图,其中UUID“*”的部分我想忽略。 二 方法 方法1 通过Beyond Co…

开放大世界的碰撞与物理

众所周知,物理开销一直是 CPU 的一个大头,而且还很容易出问题。对于开放世界,该如何进行物理运算,以及采用什么方案计算碰撞。 本文针对这个问题做了一些细微的研究,算是对 Unity 下的解决方案有了一个大致的方向。 1、…

《“草莓”引领风潮:全能AI与专业型AI的未来市场较量》

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Vmware下安装Rocky Linux9.4

Rocky Linux简介 Rocky Linux是一个开源、社区拥有和管理、免费的企业Linux发行版,提供强大的生产级平台。可作为CentOS停止维护后的替代方案。 下载Rocky Linux 下载地址 Download - Rocky Linux 根据电脑实际情况选择对应版本的Linux,这里下载AMD/In…

springboot在线办公小程序论文源码调试讲解

第二章 技术介绍 2.1 B/S结构 随着软件系统的不断改进和升级,B/S结构产品更为方便的特征体现地十分明显。对于一个中等偏大的公司来说,如果系统管理员每天要在很多台电脑之间来回查看,不断奔走,那么效率和工作量就会变得很低&…

HSE软件组件有哪些?如何实现HSE与主机的通信(同步/异步)?如何使用HSE提供的安全服务?

《S32G3系列芯片——Boot详解》系列——HSE软件组件有哪些?如何实现HSE与主机的通信(同步/异步)?如何使用HSE提供的安全服务? 一、HSE子系统软件组件1.1 NXP交付用户的HSE固件内容1.2 HSE固件提供的安全服务1.3 HSE固件…

代码随想录刷题day15丨110.平衡二叉树,257. 二叉树的所有路径, 404.左叶子之和 ,222.完全二叉树的节点个数

代码随想录刷题day15丨110.平衡二叉树,257. 二叉树的所有路径, 404.左叶子之和 ,222.完全二叉树的节点个数 1.题目 1.1平衡二叉树(优先掌握递归) 题目链接:110. 平衡二叉树 - 力扣(LeetCode&a…

探索数字沙龙——文本描述生成数字人3D发型的专业工具

一、引言 随着数字媒体创作领域不断发展,创作者们对于细节和真实感的要求越来越高。特别是在头发造型这一方面,如何准确地捕捉到人物的个性和情感,成为了3D建模和动画制作中的重要环节。为此,我们介绍了一款名为“数字沙龙”的3D头发造型工具,它旨在为数字媒体创作者提供…

分类预测|基于灰狼GWO优化BP神经网络的数据分类预测Matlab程序GWO-BP|基于鲸鱼WOA优化BP神经网络的数据分类预测Matlab程序WOA-BP

分类预测|基于灰狼GWO优化BP神经网络的数据分类预测Matlab程序GWO-BP|基于鲸鱼WOA优化BP神经网络的数据分类预测Matlab程序WOA-BP 文章目录 前言分类预测|基于灰狼GWO优化BP神经网络的数据分类预测Matlab程序GWO-BP|基于鲸鱼WOA优化BP神经网络的数据分类预测Matlab程序WOA-BP 一…

系统编程-多线程1

多线程1 目录 多线程1 引入 认识线程 1、线程的概念 2、线程的优缺点 3、进程和线程的区别和联系 4、什么时候选进程,什么时候选线程? 线程相关函数 1、创建线程 2、线程的退出函数 3、阻塞等待线程退出 并回收资源 4、获取自身线程号的函数…

算法设计:实验一分治与递归

【实验目的】 深入理解分治法的算法思想,应用分治法解决实际的算法问题。 【实验内容与要求】 设有n2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表: 1.每个选手必须与其他n-1个选手各赛一次;2.每个选手一天只能赛一…

[Algorithm][综合训练][消减整数][最长上升子序列(二)][春游]详细讲解

目录 1.消减整数1.题目链接2.算法原理详解 && 代码实现 2.最长上升子序列(二)1.题目链接2.算法原理详解 && 代码实现 3.春游1.题目链接2.算法原理详解 && 代码实现 1.消减整数 1.题目链接 消减整数 2.算法原理详解 && 代码实现 解法&#x…