一、自然语言处理(NLP)简介
NLP,自然语言处理就是用计算机来分析和生成自然语言(文本、语音),目的是让人类可以用自然语言形式跟计算机系统进行人机交互,从而更便捷、有效地进行信息管理。
NLP是人工智能领域历史较为悠久的领域,但由于语言的复杂性(语言表达多样性/歧义/模糊等等),如今的发展及收效相对缓慢。比尔·盖茨曾说过,"NLP是 AI 皇冠上的明珠。" 在光鲜绚丽的同时,却可望而不可及(...)。
为了揭开NLP的神秘面纱,本文接下来会梳理下NLP流程、主要任务及算法,并最终落到实际NLP项目(经典的文本分类任务的实战)。顺便说一句,个人水平有限,不足之处还请留言指出~~
二、NLP主要任务及技术
NLP任务可以大致分为词法分析、句法分析、语义分析三个层面。具体的,本文按照单词-》句子-》文本做顺序展开,并介绍各个层面的任务及对应技术。本节上半部分的分词、命名实体识别、词向量等等可以视为NLP基础的任务。下半部分的句子关系、文本生成及分类任务可以看做NLP主要的应用任务。
这里,贴一张自然语言处理的技术路线图,介绍了NLP任务及主流模型的分支:
高清图可如下路径下载(原作者graykode):https://github.com/aialgorithm/AiPy/tree/master/Ai%E7%9F%A5%E8%AF%86%E5%9B%BE%E5%86%8C/Ai_Roadmap
2.1 数据清洗 + 分词(系列标注任务)
- 数据语料清洗。我们拿到文本的数据语料(Corpus)后,通常首先要做的是,分析并清洗下文本,主要用正则匹配删除掉数字及标点符号(一般这些都是噪音,对于实际任务没有帮助),做下分词后,删掉一些无关的词(停用词),对于英文还需要统一下复数、语态、时态等不同形态的单词形式,也就是词干/词形还原。
- 分词。即划分为词单元(token),是一个常见的序列标注任务。对于英文等拉丁语系的语句分词,天然可以通过空格做分词,
对于中文语句,由于中文词语是连续的,可以用结巴分词(基于trie tree+维特比等算法实现最大概率的词语切分)等工具实现。
importjieba jieba.lcut("我的地址是上海市松江区中山街道华光药房") >>>['我','的','地址','是','上海市','松江区','中山','街道','华光','药房']
- 英文分词后的词干/词形等还原(去除时态 语态及复数等信息,统一为一个“单词”形态)。这并不是必须的,还是根据实际任务是否需要保留时态、语态等信息,有WordNetLemmatizer、 SnowballStemmer等方法。
- 分词及清洗文本后,还需要对照前后的效果差异,在做些微调。这里可以统计下个单词的频率、句长等指标,还可以通过像词云等工具做下可视化~
fromwordcloudimportWordCloud ham_msg_cloud=WordCloud(width=520,height=260,max_font_size=50,background_color="black",colormap='Blues').generate(原文本语料) plt.figure(figsize=(16,10)) plt.imshow(ham_msg_cloud,interpolation='bilinear') plt.axis('off')#turnoffaxis plt.show()
2.2 词性标注(系列标注任务)
词性标注是对句子中的成分做简单分析,区分出分名词、动词、形容词之类。对于句法分析、信息抽取的任务,经过词性标注后的文本会带来很大的便利性(其他方面的应用好像比较少)。
常用的词性标注有基于规则、统计以及深度学习的方法,像HanLP、结巴分词等工具都有这个功能。
2.3 命名实体识别(系列标注任务)
命名实体识别(Named Entity Recognition,简称NER)是一个有监督的系列标注任务,又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、时间、专有名词等关键信息。
通过NER识别出一些关键的人名、地名就可以很方便地提取出“某人去哪里,做什么事的信息”,很方便信息提取、问答系统等任务。NER主流的模型实现有BiLSTM-CRF、Bert-CRF,如下一个简单的中文ner项目:https://github.com/Determined22/zh-NER-TF
2.4 词向量(表示学习)
对于自然语言文本,计算机无法理解词后面的含义。输入模型前,首先要做的就是词的数值化表示,常用的转化方式有2种:One-hot编码、词嵌入分布式方法。
- One-hot编码:最简单的表示方法某过于onehot表示,每个单词是否出现就用一位数单独展示。进一步,句子的表示也就是累加每个单词的onehot,也就是常说的句子的词袋模型(bow)表示。
##词袋表示 fromsklearn.feature_extraction.textimportCountVectorizer bow=CountVectorizer( analyzer='word', strip_accents='ascii', tokenizer=[], lowercase=True, max_features=100, )
- 词嵌入分布式表示:自然语言的单词数是成千上万的,One-hot编码会有高维、词语间无联系的缺陷。这时有一种更有效的方法就是——词嵌入分布式表示,通过神经网络学习构造一个低维、稠密,隐含词语间关系的向量表示。常见有Word2Vec、Fasttext、Bert等模型学习每个单词的向量表示,在表示学习后相似的词汇在向量空间中是比较接近的。
#Fasttextembed模型 fromgensim.modelsimportFastText,word2vec model=FastText(text,size=100,sg=1,window=3,min_count=1,iter=10,min_n=3,max_n=6,word_ngrams=1,workers=12) print(model.wv['hello'])#词向量 model.save('./data/fasttext100dim')
特别地,正因为Bert等大规模自监督预训练方法,又为NLP带来了春天~
- 对于学习后的词表示向量,还可以通过重要程度进行特征加权,合适的加权方法对于任务可以有不错的提升效果。常用的有卡方chi2、TF-IDF等加权方法。TF-IDF是一种基于统计的方法,其核心思想是假设字词的重要性与其在某篇文章中出现的比例成正比,与其在其他文章中出现的比例成反比。
#TF-IDF可以直接调用sklearn fromsklearn.feature_extraction.textimportTfidfTransformer
2.5 句法、语义依存分析
句法、语义依存分析是传统自然语言的基础句子级的任务,语义依存分析是指在句子结构中分析实词和实词之间的语义关系,这种关系是一种事实上或逻辑上的关系,且只有当词语进入到句子时才会存在。语义依存分析的目的即回答句子的”Who did what to whom when and where”的问题。例如句子“张三昨天告诉李四一个秘密”,语义依存分析可以回答四个问题,即谁告诉了李四一个秘密,张三告诉谁一个秘密,张三什么时候告诉李四一个秘密,张三告诉李四什么。
传统的自然语言处理多是参照了语言学家对于自然语言的归纳总结,通过句法、语义分析可以挖掘出词语间的联系(主谓宾、施事受事等关系),用于制定文本规则、信息抽取(如正则匹配叠加语义规则应用于知识抽取或者构造特征)。可以参考spacy库、哈工大NLP的示例:http://ltp.ai/demo.html
随着深度学习技术RNN/LSTM等强大的时序模型(sequential modeling)和词嵌入方法的普及,能够在一定程度上刻画句子的隐含语法结构,学习到上下文信息,已经逐渐取代了词法、句法等传统自然语言处理流程。