资源技术动态自然语言处理

自然语言处理

2019-09-19 | |  149 |   0

原标题:自然语言处理     来源:CSDN      

原文链接:http://cloud.tusaishared.com.cn/resources/detail.do?id=1860


自然语言处理

  • 定义

    自然语言处理,简称NLP,是一种利用计算机为工具对人类特有的书面形式、口头形式的自然语言信息进行各种类型处理和加工的技术

  • 核心问题

    文本分类、关键词提取、情感分析、语义消歧、主题模型、机器翻译、问题回答、汉语分词、垂直领域的对话机器人

NLTK

  1. Tokenization(标记化/分词)

    文本是不能成段送入模型中进行分析的,我们通常会把文本切成独立含义的字、词或者短语,这个过程叫做Tokenization,这通常是大家结果自然语言处理问题的第一步。在NLTK中提供了两种不同方式的tokenization,sentence tokenization和work tokenization,前者把文本进行断句,后者对文本进行分词

  2. 简单使用

     import nltk
     from nltk import word_tokenize, sent_tokenize
     corpus = open('./data/test.txt','r').read()
     # 断句
     sentences = sent_tokenize(corpus)
     # 分词
     words = word_tokenize(corpus)


  3. 停用词

    在自然语言处理的很多任务中,我们处理的主体“文本”中有一些功能词经常出现,然而对于最后的任务目标并没有帮助,甚至会对统计方法带来一些干扰,我们把这类词叫做停用词,通常我们会用一个停用词表把它们过滤出来。比如英语当中的定冠词/不定冠词(a,an,the等)。

     # 导入内置停用词
     from nltk.corpus import stopwords
     stop_words = stopwords.words('english')
     filtered_corpus = [w for w in words if not w in stop_words]


  4. 词性标注

    词性(part-of-speech)是词汇基本的语法属性,通常也称为词性。

    词性标注(part-of-speech tagging),又称为词类标注或者简称标注,是指为分词结果中的每个单词标注一个正确的词性的程序,也即确定每个词是名词、动词、形容词或者其他词性的过程。

    词性标注是很多NLP任务的预处理步骤,如句法分析,经过词性标注后的文本会带来很大的便利性,但也不是不可或缺的步骤。 词性标注的最简单做法是选取最高频词性,主流的做法可以分为基于规则和基于统计的方法,包括:
    a. 基于最大熵的词性标注
    b. 基于统计最大概率输出词性
    c. HMM的词性标注

     from nltk import pos_tag
     tags = pos_tag(filtered_corpus)


  5. chunking/组块分析

    分块是命名实体识别的基础,词性给出来的句子成分的属性,但有时候,更多的信息(比如句子句法结构)可以帮助我们对句子中的模式挖掘更充分。举个例子,”古天乐赞助了很多小学“中的头部古天乐是一个人名(命名实体)

    组块分析是一个非常有用的从文本抽取信息的方法,提取组块需要用到正则表达式:

     from nltk.chunk import RegexpParser
     from nltk import sent_tokenize,word_tokenize
     # 写一个匹配名词的模式
     pattern = """
         NP: {<JJ>*<NN>+}
         {<JJ>*<NN><CC>*<NN>+}
         """
     # 定义组块分析器
     chunker = RegexpParser(pattern)
     # 一段文本
     text = """
     he National Wrestling Association was an early professional wrestling sanctioning body created in 1930 by 
     the National Boxing Association (NBA) (now the World Boxing Association, WBA) as an attempt to create
     a governing body for professional wrestling in the United States. The group created a number of "World" level 
     championships as an attempt to clear up the professional wrestling rankings which at the time saw a number of 
     different championships promoted as the "true world championship". The National Wrestling Association's NWA 
     World Heavyweight Championship was later considered part of the historical lineage of the National Wrestling 
     Alliance's NWA World Heavyweight Championship when then National Wrestling Association champion Lou Thesz 
     won the National Wrestling Alliance championship, folding the original championship into one title in 1949."""
     # 分句
     tokenized_sentence = nltk.sent_tokenize(text)
     # 分词
     tokenized_words = [nltk.word_tokenize(sentence) for sentence in tokenized_sentence]
     # 词性标注
     tagged_words = [nltk.pos_tag(word) for word in tokenized_words]
     # 识别NP组块
     word_tree = [chunker.parse(word) for word in tagged_words]
     word_tree[0].draw() # 会跳出弹窗,显示如下的解析图


  6. 命名实体识别

    命名实体识别(Named Entity Recognition,简称NER),又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。通常包括两部分:1) 实体边界识别;2) 确定实体类别(人名、地名、机构名或其他)。

     from nltk import ne_chunk, pos_tag,  word_tokenize
     sentence = "John studies at Stanford University."
     print(ne_chunk(pos_tag(word_tokenize(sentence))))


  7. Stemming和Lemmatizing

    很多时候我们需要对英文当中的时态语态等做归一化,这个时候我们就需要stemming和lemmatizing这样的操作了。比如"running"是进行时,但是这个词表征的含义和"run"是一致的,我们在识别语义的时候,希望能消除这种差异化。

     # 可以用PorterStemmer
     from nltk.stem import PorterStemmer
     stemmer = PorterStemmer()
     stemmer.stem("running")
     stemmer.stem("makes")
     stemmer.stem("swimming")
     # 也可以用
     from nltk.stem import SnowballStemmer
     stemmer2 = SnowballStemmer("english")
     stemmer2.stem("growing")
     # Lemmatization和Stemmer很类似,不同的地方在于它还考虑了词义关联等信息
     # Stemmer的速度更快,但是它通常只是一系列的规则
     from nltk.stem import WordNetLemmatizer
     lemmatizer = WordNetLemmatizer()
     lemmatizer.lemmatize("makes")


  8. WordNet与词义分析

     from nltk.corpus import wordnet as wn
     wn.synsets('man')
     # 第一种词义
     wn.synsets('man')[0].definition()
     # 第二种词义
     wn.synsets('man')[1].definition()
     wn.synsets('dog')
     # 查词义
     wn.synsets('dog')[0].definition()
     # 造句
     dog = wn.synset('dog.n.01')
     dog.examples()[0]
     # 上位词
     dog.hypernyms()

spaCy

  • 简单使用

      import spacy
      nlp = spacy.load('en')
      doc = nlp('Hello World! My name is HanXiaoyang')
      for token in doc:
          print('"' + token.text + '"')
      #每个token对象有着非常丰富的属性,如下的方式可以取出其中的部分属性。
      doc = nlp("Next week I'll   be in Shanghai.")
      for token in doc:
          print("{0}t{1}t{2}t{3}t{4}t{5}t{6}t{7}".format(
              token.text,
              token.idx,
              token.lemma_,
              token.is_punct,
              token.is_space,
              token.shape_,
              token.pos_,
              token.tag_
          ))
      # 断句
      doc = nlp("Hello World! My name is HanXiaoyang")
      for sent in doc.sents:
          print(sent)


  • 词性标注

      # 词性标注
      doc = nlp("Next week I'll be in Shanghai.")
      print([(token.text, token.tag_) for token in doc])


  • 命名实体识别

    命名实体识别(Named Entity Recognition,简称NER),又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。通常包括两部分:1) 实体边界识别;2) 确定实体类别(人名、地名、机构名或其他)。

      doc = nlp("Next week I'll be in Shanghai.")
      for ent in doc.ents:
          print(ent.text, ent.label_)
      from nltk.chunk import conlltags2tree
      
      doc = nlp("Next week I'll be in Shanghai.")
      iob_tagged = [
          (
              token.text, 
              token.tag_, 
              "{0}-{1}".format(token.ent_iob_, token.ent_type_) if token.ent_iob_ != 'O' else token.ent_iob_
          ) for token in doc
      ]
       
      print(iob_tagged)
      # 按照nltk.Tree的格式显示
      print(conlltags2tree(iob_tagged))

spaCy中包含的命名实体非常丰富,如下例所示:

doc = nlp("I just bought 2 shares at 9 a.m. because the stock went up 30% in just 2 days according to the WSJ")
for ent in doc.ents:
    print(ent.text, ent.label_)123

还可以用非常漂亮的可视化做显示:

from spacy import displacy
 
doc = nlp('I just bought 2 shares at 9 a.m. because the stock went up 30% in just 2 days according to the WSJ')
displacy.render(doc, style='ent', jupyter=True)1234
  • chunking/组块分析

      doc = nlp("Wall Street Journal just published an interesting piece on crypto currencies")
      for chunk in doc.noun_chunks:
          print(chunk.text, chunk.label_, chunk.root.text)


  • 句法依存解析

      doc = nlp('Wall Street Journal just published an interesting piece on crypto currencies')
       
      for token in doc:
          print("{0}/{1} <--{2}-- {3}/{4}".format(
              token.text, token.tag_, token.dep_, token.head.text, token.head.tag_))
      from spacy import displacy
       
      doc = nlp('Wall Street Journal just published an interesting piece on crypto currencies')
      displacy.render(doc, style='dep', jupyter=True, options={'distance': 90})


  • 词向量使用

    NLP中有一个非常强大的文本表示学习方法叫做word2vec,通过词的上下文学习到词语的稠密向量化表示,同时在这个表示形态下,语义相关的词在向量空间中会比较接近。也有类似v(爷爷)-v(奶奶) ≈ v(男人)-v(女人)的关系。

      nlp = spacy.load('en_core_web_lg')
      print(nlp.vocab['banana'].vector)
      from scipy import spatial
      
      # 余弦相似度计算
      cosine_similarity = lambda x, y: 1 - spatial.distance.cosine(x, y)
      
      # 男人、女人、国王、女王 的词向量
      man = nlp.vocab['man'].vector
      woman = nlp.vocab['woman'].vector
      queen = nlp.vocab['queen'].vector
      king = nlp.vocab['king'].vector
       
      # 我们对向量做一个简单的计算,"man" - "woman" + "queen"
      maybe_king = man - woman + queen
      computed_similarities = []
      
      # 扫描整个词库的词向量做比对,召回最接近的词向量
      for word in nlp.vocab:
          if not word.has_vector:
              continue
       
          similarity = cosine_similarity(maybe_king, word.vector)
          computed_similarities.append((word, similarity))
      
      # 排序与最接近结果展示
      computed_similarities = sorted(computed_similarities, key=lambda item: -item[1])
      print([w[0].text for w in computed_similarities[:10]])


  • 词汇与文本相似度

      # 词汇语义相似度(关联性)
      banana = nlp.vocab['banana']
      dog = nlp.vocab['dog']
      fruit = nlp.vocab['fruit']
      animal = nlp.vocab['animal']
       
      print(dog.similarity(animal), dog.similarity(fruit)) # 0.6618534 0.23552845
      print(banana.similarity(fruit), banana.similarity(animal)) # 0.67148364 0.2427285
      # 文本语义相似度(关联性)
      target = nlp("Cats are beautiful animals.")
       
      doc1 = nlp("Dogs are awesome.")
      doc2 = nlp("Some gorgeous creatures are felines.")
      doc3 = nlp("Dolphins are swimming mammals.")
       
      print(target.similarity(doc1))  # 0.8901765218466683
      print(target.similarity(doc2))  # 0.9115828449161616
      print(target.similarity(doc3))  # 0.7822956752876101


中文文本基本任务与处理

  • 分词

    对于中文和日文这样的特殊亚洲语系文本而言,字和字之间是紧密相连的,单纯从文本形态上无法区分具备独立含义的词(拉丁语系纯天然由空格分隔不同的word),而不同的词以不同的方式排布,可以表达不同的内容和情感,因此在很多中文任务中,我们需要做的第一个处理叫做分词。

    这是一个非常基础的功能,但是会较大程度影响下游任务(机器翻译、情感分析、文本理解)的效果。

    目前主流的分词方法主要是基于词典匹配的分词方法(正向最大匹配法、逆向最大匹配法和双向匹配分词法等)和基于统计的分词方法(HMM、CRF、和深度学习);主流的分词工具库包括 中科院计算所NLPIR、哈工大LTP、清华大学THULAC、Hanlp分词器、Python jieba工具库等。

  • 停用词与N-gram

    N-gram在中文中叫做n元语法,指文本中连续出现的n个语词。n元语法模型是基于(n-1)阶马尔可夫链的一种概率语言模型,通过n个语词出现的概率来推断语句的结构。关于语言模型的更多内容,我们在后续的课程会详细提到。

  • 词性标注

  • 句法依存分析

  • 命名实体识别

  • 关键词抽取

jieba工具使用

  • 基本分词函数与用法

    jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode)
    jieba.cut 方法接受三个输入参数:
    a. 需要分词的字符串
    b. cut_all 参数用来控制是否采用全模式
    c. HMM 参数用来控制是否使用 HMM 模型
    jieba.cut_for_search 方法接受两个参数
    a. 需要分词的字符串
    b. 是否使用 HMM 模型。

      # encoding=utf-8
      import jieba
      
      seg_list = jieba.cut("我在网易云课堂学习自然语言处理", cut_all=True)
      print("Full Mode: " + "/ ".join(seg_list))  # 全模式
      
      seg_list = jieba.cut("我在网易云课堂学习自然语言处理", cut_all=False)
      print("Default Mode: " + "/ ".join(seg_list))  # 精确模式
      
      seg_list = jieba.cut("他毕业于北京航空航天大学,在百度深度学习研究院进行研究")  # 默认是精确模式
      print(", ".join(seg_list))
      
      seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在斯坦福大学深造")  # 搜索引擎模式
      print(", ".join(seg_list))


  • 添加用户字典

    很多时候我们需要针对自己的场景进行分词,会有一些领域内的专有词汇。
    1.可以用jieba.load_userdict(file_name)加载用户字典
    2.少量的词汇可以自己用下面方法手动添加:
    用 add_word(word, freq=None, tag=None) 和 del_word(word) 在程序中动态修改词典
    用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。

      print('/'.join(jieba.cut('如果放到旧字典中将出错。', HMM=False)))
      jieba.suggest_freq(('中', '将'), True)
      print('/'.join(jieba.cut('如果放到旧字典中将出错。', HMM=False)))


  • 词性标注

      import jieba.posseg as pseg
      words = pseg.cut("我在网易云课堂学习自然语言处理")
      for word, flag in words:
          print('%s %s' % (word, flag))


  • 关键词抽取

  1. 基于 TF-IDF 算法的关键词抽取

    import jieba.analyse
    jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
    a. sentence 为待提取的文本
    tb. opK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20
    c. withWeight 为是否一并返回关键词权重值,默认值为 False
    d. allowPOS 仅包括指定词性的词,默认值为空,即不筛选

     import jieba.analyse as analyse
     lines = open('data/NBA.txt').read()
     print("  ".join(analyse.extract_tags(lines, topK=20, withWeight=False, allowPOS=())))
     
     lines = open('data/西游记.txt', encoding='gb18030').read()
     print("  ".join(analyse.extract_tags(lines, topK=20, withWeight=False, allowPOS=())))


  2. 基于TextRank算法的关键词抽取

    jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意默认过滤词性。
    jieba.analyse.TextRank() 新建自定义 TextRank 实例

    基本思想:
    将待抽取关键词的文本进行分词
    以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
    计算图中节点的PageRank,注意是无向带权图

     import jieba.analyse as analyse
     lines = open('data/NBA.txt').read()
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))
     print("---------------------我是分割线----------------")
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n'))))
     lines = open('data/西游记.txt', encoding='gb18030').read()
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))


  3. 使用

     import jieba.analyse as analyse
     lines = open('data/NBA.txt').read()
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))
     print("---------------------我是分割线----------------")
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n'))))
     
     lines = open('data/西游记.txt', encoding='gb18030').read()
     print("  ".join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))))


  4. 可视化

     import warnings
     warnings.filterwarnings("ignore")
     import jieba    #分词包
     import numpy    #numpy计算包
     import codecs   #codecs提供的open方法来指定打开的文件的语言编码,它会在读取的时候自动转换为内部unicode 
     import pandas as pd  
     import matplotlib.pyplot as plt
     %matplotlib inline
     import matplotlib
     matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
     from wordcloud import WordCloud#词云包
     
     # pandas读取数据
     df = pd.read_csv("./data/entertainment_news.csv", encoding='utf-8').dropna()
     # 转成list
     content=df["content"].values.tolist()
     # 分词与统计词频
     segment=[]
     for line in content:
         try:
             segs=jieba.lcut(line)
             for seg in segs:
                 if len(seg)>1 and seg!='rn':
                     segment.append(seg)
         except:
             print(line)
             continue
     
     words_df=pd.DataFrame({'segment':segment})
     stopwords=pd.read_csv("data/stopwords.txt",index_col=False,quoting=3,sep="t",names=['stopword'], encoding='utf-8')#quoting=3全不引用
     words_df=words_df[~words_df.segment.isin(stopwords.stopword)]
     
     words_stat=words_df.groupby(by=['segment'])['segment'].agg({"计数":numpy.size})
     words_stat=words_stat.reset_index().sort_values(by=["计数"],ascending=False)
     words_stat.head()
     
     matplotlib.rcParams['figure.figsize'] = (10.0, 6.0)
     wordcloud=WordCloud(font_path="data/simhei.ttf",background_color="black",max_font_size=80)
     word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
     wordcloud=wordcloud.fit_words(word_frequence)
     plt.imshow(wordcloud)
     
     from scipy.misc import imread
     matplotlib.rcParams['figure.figsize'] = (15.0, 15.0)
     from wordcloud import WordCloud,ImageColorGenerator
     bimg=imread('image/entertainment.jpeg')
     wordcloud=WordCloud(background_color="white",mask=bimg,font_path='data/simhei.ttf',max_font_size=200)
     word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
     wordcloud=wordcloud.fit_words(word_frequence)
     bimgColors=ImageColorGenerator(bimg)
     plt.axis("off")
     plt.imshow(wordcloud.recolor(color_func=bimgColors))


  5. 排序使用

     import jieba.analyse as analyse
     import pandas as pd
     df = pd.read_csv("./data/technology_news.csv", encoding='utf-8').dropna()
     lines=df.content.values.tolist()
     content = "".join(lines)
     print(analyse.extract_tags(content, topK=30, withWeight=False, allowPOS=()))
     
     import jieba.analyse as analyse
     import pandas as pd
     df = pd.read_csv("./data/military_news.csv", encoding='utf-8').dropna()
     lines=df.content.values.tolist()
     content = "".join(lines)
     print(analyse.extract_tags(content, topK=30, withWeight=False, allowPOS=()))
     
     #TextRank
     import jieba.analyse as analyse
     import pandas as pd
     df = pd.read_csv("./data/military_news.csv", encoding='utf-8')
     df = df.dropna()
     lines=df.content.values.tolist()
     content = "".join(lines)
     
     print(analyse.textrank(content, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')))
     print("---------------------我是分割线----------------")
     print(analyse.textrank(content, topK=20, withWeight=False, allowPOS=('ns', 'n')))

THE END

免责声明:本文来自互联网新闻客户端自媒体,不代表本网的观点和立场。

合作及投稿邮箱:E-mail:editor@tusaishared.com

上一篇:5分钟弄懂语音识别技术原理

下一篇:多图带你读懂 Transformers 的工作原理

用户评价
全部评价

热门资源

  • 应用笔画宽度变换...

    应用背景:是盲人辅助系统,城市环境中的机器导航...

  • GAN之根据文本描述...

    一些比较好玩的任务也就应运而生,比如图像修复、...

  • 端到端语音识别时...

    从上世纪 50 年代诞生到 2012 年引入 DNN 后识别效...

  • 人体姿态估计的过...

    人体姿态估计是计算机视觉中一个很基础的问题。从...

  • 谷歌发布TyDi QA语...

    为了鼓励对多语言问答技术的研究,谷歌发布了 TyDi...