当前位置: 首页 > 科技观察

NLP:不要重新发明轮子

时间:2023-03-12 13:48:08 科技观察

介绍自然语言处理(NLP)是一个令人生畏的领域名称。从非结构化文本中得出有用的结论很困难,而且有无数的技术和算法,每种都有自己的用例和复杂性。作为对NLP接触最少的开发人员,可能很难知道使用哪些方法以及如何实现它们。如果我以最小的努力提供尽可能完美的结果。使用80/20原则,我将向您展示如何在不显着牺牲结果(80%)的情况下快速提供解决方案(20%)。“80/20原则指出,少数原因、投入或努力通常会导致大部分结果、输出或回报”-80/20原则的作者理查德·科赫我们将如何实现这一目标?有一些非常棒的Python库!我们可能站在巨人的肩膀上快速创新,而不是重新发明轮子。通过预先测试的实施和预先训练的模型,我们将专注于应用这些方法并提供价值。本文面向希望将自然语言处理快速集成到其项目中的开发人员。在强调易用性和快速结果的同时,性能也有所下降。根据我的经验,80%的技术对项目来说已经足够了,但是你也可以从其他地方找到相关的方法。事不宜迟,让我们开始吧!什么是自然语言处理?允许软件自动处理文本的智能子领域。NLP使机器能够阅读、理解和响应杂乱无章和非结构化的文本。人们通常将NLP视为机器学习的一个子集,但现实情况更为微妙。一些NLP工具依赖机器学习,有些甚至使用深度学习。然而,这些方法通常依赖于大型数据集并且难以实现。相反,我们将专注于更简单、基于规则的方法来加快开发周期。术语以最小的数据单位开始,字符是单个字母、数字或标点符号。单词是字符列表,句子是单词列表。文档是句子列表,而语料库是文档列表。预处理可能是NLP项目中最重要的步骤,预处理涉及清理输入,以便模型可以忽略噪音并专注于最重要的内容。强大的预处理流水线将提高所有模型的性能,因此必须强调其价值。以下是一些常见的预处理步骤:分割:给定一长串字符,我们可以按空格分隔文档、按句点分隔句子和按空格分隔单词。实施细节因数据集而异。使用小写字母:大写字母通常不会提高性能,并且会使字符串比较更加困难。因此,将所有内容更改为小写。删除标点符号:我们可能需要删除逗号、引号和其他不增加意义的标点符号。删除停用词:停用词是像“she”、“the”和“of”这样的词,它们不会给文本增加意义,也不会分散你的关键词。删除其他不相关的词:根据您的应用程序,您可能希望删除某些不相关的词。例如,如果评估课程评论,像“教授”和“课程”这样的词可能没有用。词干提取/词形还原:词干提取和词形还原都会生成变形词的词根形式(例如:“running”到“run”)。词干提取速度更快,但不能保证词根是英文单词。词干化使用语料库来确保词根是一个词,但以速度为代价。词性标注:词性标注是以词性(名词、动词、介词)为基础,根据词义和语境对词进行标注。例如,我们可以专注于名词来进行关键词提取。这些步骤是成功预处理的基础。根据数据集和任务,您可以跳过一些步骤或添加新步骤。通过预处理手动观察数据,并在出现问题时进行修正。Python库让我们来看看NLP的两个主要Python库。这些工具将在预处理过程中发挥非常大的作用。NLTKNaturalLanguageToolkit是Python中使用最广泛的NLP库。NLTK是由UPenn出于学术目的开发的,具有大量的特征和语料库。NLTK非常适合处理数据和运行预处理:https://www.nltk.org/NLTK是构建Python程序以处理人类语言数据的领先平台。它提供了一个易于使用的API>>>importnltk>>>sentence="Ateighto'clockonThursdaymorningArthurdidn'tfeelverygood.">>>tokens=nltk.word_tokenize(sentence)>>>tokens['At','eight',"o'时钟'、'在'、'星期四'、'早上'、'亚瑟'、'做了'、'不'、'感觉'、'非常'、'好'、'。']>>>tagged=nltk.pos_tag(tokens)>>>tagged[0:6][('At','IN'),('eight','CD'),("o'clock",'JJ'),('or','IN'),('Thursday','NNP'),('morning','NN')]下面是NLTK网站上的一个例子,展示了标记句子和标记是多么容易SpaCySpaCy是一个现代图书馆.label_)#output#SebastianThrun#GoogleOrganization#2007Date我们可以使用SpaCy执行命名实体识别。许多其他任务可以使用SpaCyapi快速完成。GenSim与NLTK和SpaCy不同,GenSim专门处理信息检索(IR)问题。GenSim的开发重点是内存管理,包括许多文档相似性模型,包括潜在语义索引、Word2Vec和FastText。Gensim是一个用于主题模型、文档索引和大型语料库相似性检索的Python库。下面是一个预训练的GenSimWord2Vec模型示例,该模型用于查找单词相似性。不用担心乱七八糟的细节,我们可以很快得到结果。importgensim.downloaderasapiwv=api.load("word2vec-google-news-300")pairs=[('car','minivan'),#minivanisakindofcar('car','bicycle'),#也有轮子的车辆('car','airplane'),#withoutwheels,butstillvehicles('car','cereal'),#...etc('car','communism'),]forw1,w2inpairs:print('%r\t%r\t%.2f%(w1,w2,wv.similarity(w1,w2)))#output#'car''minivan'0.69#'car''bicycle'0.54#'car''airplane'0.42#'car''cereal'0.14#'car''communism'0.06等等……这个列表并不全面,但涵盖了一些用例。应用程序现在我们已经讨论了预处理方法和Python库,让我们通过一些示例将它们放在一起。对于每种算法,我将介绍几种NLP算法,根据我们的快速开发目标选择一种,并使用其中一个库创建一个简单的实现。应用1:预处理预处理是任何NLP解决方案的关键部分,所以让我们看看如何使用Python库来加快处理速度。根据我的经验,NLTK拥有我们需要的所有工具,并针对独特的用例进行了定制。让我们加载一个示例语料库:importnltk#加载棕色语料库corpus=nltk.corpus.brown#访问语料库文件print(corpus.fileids())#output['ca01','ca02','ca03','ca04','ca05','ca06','ca07','ca08','ca09','ca10','ca11','ca12','ca13','ca14','ca15','ca16','ca17','ca18','ca19','ca20','ca21','ca22','ca23','ca24','ca25','ca26','ca27','ca28','ca29','ca30','ca31','ca32','ca33','ca34','ca35','ca36','ca37','ca38','ca39','ca40','ca41','ca42','ca43','ca44','cb01','cb02','cb03','c...根据上面定义的pipeline,我们可以使用NLTK实现分词,去除标点符号和停用词,执行词干提取等。看看删除停用词有多容易:fromnltk.corpusimportstopwordssw=stopwords.words("english")sw+=""#emptystringdefremove_sw(doc):sentences=[]forsentenceindoc:sentence=[wordforwordinsentenceifwordnotinsw]sentences.append(sentence)返回句子print("WithStopwords")print(doc1[1])print()doc1=remove_sw(doc1)print("WithoutStopwords")print(doc1[1])#output#hasstopwords#['the','jury','further','said','in','presentations','that','the','city','executive','committee','which','had',#'charge','of','the','election','deserves','the','praise','and','thanks','of','the','city','of','atlanta','for',#'the','manner','in','which','the','election','was','conducted']#无停用词#['jury','said','presentations','city','executive','committee','charge','election','deserves','praise','thanks','city',#'atlanta','manner','election','conducted']整个预处理管道用了我不到40行Python。在此处查看完整代码。请记住,这是一个通用示例,您应该根据特定用例的需要修改流程。应用2:文档聚类文档聚类是自然语言处理中的一项常见任务,因此让我们讨论一些方法。这里的基本思想是为每个文档分配一个代表所讨论主题的向量:如果向量是二维的,我们可以像上面那样可视化文档。在此示例中,我们看到文档A和B密切相关,而D和F松散相关。即使这些向量是3维、100维或1000维,使用距离度量,我们也可以计算相似度。下一个问题是如何使用非结构化文本输入为每个文档构建这些向量。这里有几个选项,从最简单到最复杂:Bagofwords:为每个唯一的单词分配一个索引。给定文档的向量是每个单词出现的频率。TF-IDF:根据其他文档中的常用词来增强表示。如果两个文档共享一个罕见词,则它们比共享一个常用词更相似。潜在语义索引(LSI):词袋和TF-IDF可以创建高维向量,这会降低距离测量的准确性。LSI将这些向量压缩到更易于管理的大小,同时最大限度地减少信息丢失。Word2Vec:使用神经网络从大型文本语料库中学习单词关联。然后将每个单词的向量相加得到一个文档向量。Doc2Vec:建立在Word2Vec之上,但使用更好的方法从词向量列表中近似文档向量。Word2Vec和Doc2Vec非常复杂,需要大型数据集来学习词嵌入。我们可以使用预训练模型,但它们可能无法很好地适应领域中的任务。相反,我们将使用词袋、TF-IDF和LSI。现在选择我们的图书馆。GenSim是专门为此任务构建的,它包含所有三种算法的简单实现,所以让我们使用GenSim。对于这个例子,让我们再次使用Brown语料库。它有15个文本类别的文档,如“冒险”、“编辑”、“新闻”等。运行我们的NLTK预处理例程后,我们可以开始应用GenSim模型。首先,我们创建一个将ids映射到唯一索引的字典。fromgensimimportcorpora,models,similaritiesdictionary=corpora.Dictionary(corpus)dictionary.filter_n_most_frequent(1)#removes""num_words=len(dictionary)print(dictionary)print()print("MostFrequentWords")top10=sorted(dictionary.cfs.items(),key=lambdax:x[1],reverse=True)[:10]fori,(id,freq)inenumerate(top10):打印(i,freq,dictionary[id])#output#Dictionary(33663uniquetokens:['1','10','125','15th','16']...)#最后数量的词#03473one#12843would#22778say#32327make#41916time#51816go#61777could#71665new#81659year#91575take接下来,我们迭代地应用词袋、TF-IDF和潜在语义索引:corpus_bow=[dictionary.doc2bow(doc)fordocincorpus]print(len(corpus_bow[0]))print(corpus_bow[0][:20])#output#6106#[(0,1),(1,3),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,2),(10,1),(11,1),(12,2),(13,2),(14,2),(15,#1),(16,2),(17,2),(18,3),(19,1)]tfidf_model=models.TfidfModel(corpus_bow)corpus_tfidf=tfidf_model[corpus_bow]print(len(corpus_tfidf[0]))print(corpus_tfidf[0][:20])#output#5575#[(0,0.001040495879718581),(1,0.0011016669638018743),(2,0.002351365659027428),(3,0.002351365659027428),(4,#0.0013108697793088472),(5,0.005170600993729588),(6,0.003391861538746009),(7,0.004130105114011007),(8,#0.003391861538746009),(9,0.008260210228022013),(10,0.004130105114011007),(11,0.00195578??7484706956),(12,#0.0015918258736505996),(13,0.0015918258736505996),(14,0.008260210228022013),(15,0.0013108697793088472),(16,#0.0011452524080876978),(17,0.002080991759437162),(18,0.004839366251287288),(19,0.0013108697793088472)]lsi_model=models.LsiModel(corpus_tfidf,id2word=dictionary,num_topics=20)corpus_lsi=lsi_model[corpus_tfidf]print(len(corpus_lsi[0]))print(corpus_lsi[0])#输出#15#[(0,0.18682238167974372),(1,-0.4437583954806601),(2,0.22275580411969662),(3,0.06534575527078117),(4,#-0.10021080420155845),(5,0.06653745783577146),(6,0.05025291839076259),(7,0.7117552624193217),(8,-0.3768886513901333),(9,#0.1650380936828472),(10,0.13664364557932132),(11,-0.03947144082104315),(12,-0.03177275640769521),(13,#-0.00890543444745628),(14,-0.009715808633565214)]在大约10行Python代码中,我们处理了三个独立的模型,并使用余弦相似度提取文档的向量表示进行向量比较,最相似的文档可以是成立。类别=[“冒险”,“belles_lettres”,“社论”,“小说”,“政府”,“爱好”,“幽默”,“博学”,“传说”,“神秘”,“新闻”,“宗教”“评论”,“浪漫”,“科幻小说”]num_categories=len(类别)foriinrange(3):print(categories[i])sims=index[lsi_model[corpus_bow[i]]]top3=sorted(enumerate(sims),key=lambdax:x[1],reverse=True,)[1:4]forj,scoreintop3:print(score,categories[j])print()#output#adventure#0.22929086fiction#0.20346783romance#0.19324714mystery#belles_lettres#0.3659389editorial#0.3413822lore#0.33065677news#editorial#0.45590898news#0.38146105government#0.2897901belles_lettres就是这样,我们有结果了!冒险小说与浪漫小说最相似,社论与新闻和政府相似。应用3:情感分析情感分析是将非结构化文本解释为正面、负面或中性。情绪分析是分析评论、衡量品牌、构建AI聊天机器人等的有用工具。与文档聚类不同,在情感分析中我们不使用预处理。段落的标点符号、流程和上下文可以揭示很多关于情绪的信息,因此我们不想删除它们。为了简单和有效,我建议使用基于模式的情感分析。这些模型通过搜索特定关键字、句子结构和标点符号来衡量文本的积极性和消极性。以下是两个内置情感分析器的库:VADER情感分析:VADER是ValenceAwareDictionary和sEntimentRecognizer的首字母缩写,是NLTK情感分析的扩展。它使用模式来计算情绪,尤其是表情符号和短信俚语。它也很容易实现。fromvaderSentiment.vaderSentimentimportSentimentIntensityAnalyzeranalyzer=SentimentIntensityAnalyzer()print(analyzer.polarity_scores("Thisclassismyfavorite!!!"))print(analyzer.polarity_scores("Ihatethisclass:("))#output#{'neg':0.0,'neu',:0.508'pos':0.492,'compound':0.5962}#{'neg':0.688,'neu':0.312,'pos':0.0,'compound':-0.765}TextBlobSentimentAnalysis:类似的工具用于TextBlob用于情感分析。TextBlob其实是一个多功能的库,类似于NLTK和SpaCy。在情感分析工具上,它与VADER的不同之处在于报告情感极性和主观性。从我个人的经验来看,我更喜欢VADER,但各有千秋和弱点。TextBlob也很容易实现:fromtextblobimportTextBlobtestimonial=TextBlob("Thisclassismyfavorite!!!")print(testimonial.sentiment)testimonial=TextBlob("Ihatethisclass:(")print(testimonial.sentiment)#output#Sentiment(polarity=0.9765625,subjectivity=1.0)#Sentiment(polarity=-0.775,subjectivity=0.95)注意:基于模式的模型不能很好地处理上面例子中这样的小文本。我建议对平均四句文本进行情感分析。其他应用这里有几个额外的主题和一些有用的算法和工具来加速你的开发。关键字提取:使用SpaCy的命名实体识别(NER),使用ntlk-rake的快速自动关键字提取(RAKE)使用PyTextRankSpaCy扩展,使用GenSim拼写检查的TF-IDF:PyEnchant、SymSpellPython端口希望这些示例有助于展示Python中可用于NLP的大量资源。无论是什么问题,有人已经de开发了一个库来简化这个过程。使用这些库可以在短时间内产生很好的结果。提示和技巧通过对NLP的介绍、Python库的概述和一些示例应用程序,您几乎已经准备好迎接挑战了。最后,我有一些提示和技巧可以充分利用这些资源。Python工具:我推荐用于依赖管理的Poetry,用于测试新模型的JupyterNotebook,用于维护代码风格的Black和/或Flake8,用于版本管理的GitHub。保持井井有条:从一个库跳到另一个库,将代码复制到您当前编写测试的代码很容易实现,但并不好。我建议您采取更深思熟虑的方法,因为您不想在匆忙的场景中错过一个好的解决方案。预处理:垃圾进,垃圾出。实施强大的预处理管道来清理输入非常重要。目视检查处理后的文本,确保一切按预期进行。展示结果:选择展示结果的方式会产生很大的不同。如果文本输出看起来有点粗糙,请考虑显示聚合统计数据或数值结果。