NLP入门学习1——分词和词性标注

  • 0.简介
  • 1.概念和工具
  • 1.1 词性标注
  • 1.2 NLTK
  • 1.3 jieba
  • 1.4 LAC
  • 2.代码实现
  • 2.1 分词
  • 2.1.1 使用nltk进行分词:
  • 2.1.2 使用jieba进行分词
  • 2.1.3 使用LAC进行分词
  • 2.2 词性标注
  • 2.2.1 使用nltk工具实现词性标注
  • 2.2.2 使用LAC工具实现词性标注
  • 3.遇到的问题及解决
  • 3.1 Resource punkt not found
  • 4.结束


0.简介

本文主要介绍NLP中最基础的任务分词和词性标注。难度属于入门级别。
本文的主要参考如下:
参考链接1参考链接2参考链接3参考链接4

1.概念和工具

1.1 词性标注

词性标注是NLP四大基本任务中序列标注中的一项,其目的是对文本中的词汇实现词性的划分。标注的结果是一个由二元组组成的list,其中每一个二元组中标明了每个token对应的词性。

1.2 NLTK

NLTK全称natural language toolkit是一个基于python编写的自然语言处理工具箱。
安装非常简单,直接用conda或者pip安装即可。

conda install nltk

在nltk中,将词性归为以下类别:

简写

全称

含义

CC

coordinating conjunction

并列连词

CD

cardinal digit

基数

DT

determiner

限定词

EX

existentialthere

存在句

FW

foreignword

外来语

IN

preposition/subordinating conjunction

介词/从属连词

JJ

adjective

形容词

JJR

adjective, comparative

比较级形式

JJS

adjective, superlative

最高级

MD

modal

情态动词

NN

noun

名词单数形式

NNS

noun

名词复数形式

NNP

propernoun

专有名词单数形式

NNPS

propernoun

专有名词复数形式

PDT

predeterminer

前位限定词

POS

possessiveending

属有词’s

PRP

personalpronoun

人称代词

PRP$

possessive pronoun

物主代词

RB

adverb very

副词

RBR

adverb,comparative

副词比较级

RBS

adverb,superlative

副词最高级

RP

particle

与动词构成短语的副词或介词

TO

to

to

UH

interjection

感叹词

VB

verb

动词

VBD

verb

动词过去式

VBG

verb

现在分词

VBN

verb

过去分词

VBP

verb

动词现在

VBZ

verb

动词 第三人称

WDT

wh-determiner

限定词which等

WP

wh-pronoun

代词who, what 等

WP$

possessivewh-pronoun

所有格 whose

WRB

wh-abverb

where, when 副词

1.3 jieba

jieba是一个优秀的中文分词库,同样是基于python。
支持精确模式,全模式,搜索引擎模式等多种模式。
Github:jieba

jieba安装可以在conda命令行通过如下指令完成:

conda install --channel https://conda.anaconda.org/conda-forge jieba

1.4 LAC

LAC全称Lexical Analysis of Chinese,是百度自然语言处理部研发的一款联合的词法分析工具,实现中文分词、词性标注、专名识别等功能。
GitHub:LAC LAC的安装也非常简单:

pip install lac -i https://mirror.baidu.com/pypi/simple

在词性标注任务中,LAC将词性归为以下类:

NLP标注方法 nlp逻辑语言标注_百度

2.代码实现

2.1 分词

分词可以使用nltk实现,也可以使用其他工具如jieba实现。
使用nltk工具进行分词可以直接由文本到token划分,也可以先进行sentence level的分词。

2.1.1 使用nltk进行分词:

(1)直接划分

words = nltk.word_tokenize(text)
words

结果:

Out[1]: ['life', 'is', 'short', '.', 'play', 'more', 'sport', '.']

(2)先进行句子划分:

import nltk
text = 'life is short. play more sport.'
sents = nltk.sent_tokenize(text)
sents

结果:

Out[1]: ['life is short.', 'play more sport.']

再进行分词:

words = [nltk.word_tokenize(i) for i in sents]
words

结果:

Out[1]: [['life', 'is', 'short', '.'], ['play', 'more', 'sport', '.']]

但没有加载中文语料库的情况下,试图使用nltk进行中文分词就会出现问题:

words = nltk.word_tokenize('吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮')
words

结果可以看出分词并没有成功:

['吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮']

接下来就介绍可以用于中文分词的工具。

2.1.2 使用jieba进行分词

jieba的分词功能可以由两个函数实现,cut函数返回的是一个generator,lcut函数直接返回一个list,具体的使用方法:
(1) cut:

import jieba
import jieba.analyse
words = jieba.cut(text)
print('/'.join(words))

结果:

life/ /is/ /short/./ /play/ /more/ /sport/.

(2) lcut:

words = jieba.lcut(text)
print(words)

结果:

['life', ' ', 'is', ' ', 'short', '.', ' ', 'play', ' ', 'more', ' ', 'sport', '.']

在这里可以看出jieba分词与nltk之间的一个区别在于,jieba的分词结果中把空格也包含进去了,不限要空格的话就把它删掉就好了。

words = jieba.lcut(text)
while ' ' in words:
    words.remove(' ')
print(words)

结果:

['life', 'is', 'short', '.', 'play', 'more', 'sport', '.']

jieba除了可以进行英文分词,也可以进行中文分词。

words = jieba.lcut('吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮')
words

结果:

['吃', '葡萄', '不吐', '葡萄', '皮', ',', '不吃', '葡萄', '倒', '吐', '葡萄', '皮']

2.1.3 使用LAC进行分词

使用LAC进行分词也很简单,下面是LAC官方的操作指引和样例结果。

from LAC import LAC

# 装载分词模型
lac = LAC(mode='seg')

# 单个样本输入,输入为Unicode编码的字符串
text = "LAC是个优秀的分词工具"
seg_result = lac.run(text)

# 批量样本输入, 输入为多个句子组成的list,平均速率会更快
texts = ["LAC是个优秀的分词工具", "百度是一家高科技公司"]
seg_result = lac.run(texts)

结果:

【单样本】:seg_result = [LAC, 是, 个, 优秀, 的, 分词, 工具]
【批量样本】:seg_result = [[LAC, 是, 个, 优秀, 的, 分词, 工具], [百度, 是, 一家, 高科技, 公司]]

2.2 词性标注

2.2.1 使用nltk工具实现词性标注

pos_tags =nltk.pos_tag(words)
print(pos_tags)

结果:

[('life', 'NN'), ('is', 'VBZ'), ('short', 'JJ'), ('.', '.'), ('play', 'VB'), ('more', 'JJR'), ('sport', 'NN'), ('.', '.')]

可以看出在英文分词方面nltk工具的效果还是很准确,很精细的。

上文中提到nltk在中文分词中不灵了,那么如果将分好的token输入给nltk,是否能够完成词性标注了?

words = jieba.lcut('吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮')
pos_tags =nltk.pos_tag(words)
pos_tags

结果:

[('吃', 'JJ'),
 ('葡萄', 'NNP'),
 ('不吐', 'NNP'),
 ('葡萄', 'NNP'),
 ('皮', 'NNP'),
 (',', 'NNP'),
 ('不吃', 'NNP'),
 ('葡萄', 'NNP'),
 ('倒', 'NNP'),
 ('吐', 'NNP'),
 ('葡萄', 'NNP'),
 ('皮', 'NN')]

尽管标注完成了,但是通过判断发现它的标注并不准确,把“吃”标注成了形容词,“不吐”标注成了名词。

2.2.2 使用LAC工具实现词性标注

from LAC import LAC

# 装载LAC模型
lac = LAC(mode='lac')

# 单个样本输入,输入为Unicode编码的字符串
text = u"LAC是个优秀的分词工具"
lac_result = lac.run(text)

# 批量样本输入, 输入为多个句子组成的list,平均速率更快
texts = [u"LAC是个优秀的分词工具", u"百度是一家高科技公司"]
lac_result = lac.run(texts)

结果:

【单样本】: lac_result = ([百度, 是, 一家, 高科技, 公司], [ORG, v, m, n, n])
【批量样本】:lac_result = [
                    ([百度, 是, 一家, 高科技, 公司], [ORG, v, m, n, n]),
                    ([LAC, 是, 个, 优秀, 的, 分词, 工具], [nz, v, q, a, u, n, n])
                ]

再来测试一下我们自己的例子:

from LAC import LAC

# 装载LAC模型
lac = LAC(mode='lac')

# 单个样本输入,输入为Unicode编码的字符串
text = u"吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮"
lac_result = lac.run(text)

结果:

[['吃', '葡萄', '不', '吐', '葡萄皮', ',', '不', '吃', '葡萄', '倒', '吐', '葡萄皮'],
 ['v', 'nz', 'd', 'v', 'n', 'w', 'd', 'v', 'n', 'd', 'v', 'n']]

结果同样十分准确,并且相比jieba分词的结果,吧“葡萄皮”作为一个整体保留下来了。

3.遇到的问题及解决

3.1 Resource punkt not found

使用nltk分词时,报错LookupError Resource punkt not found,按照提示下载,nltk.download(‘punkt’),提示failed。
这是因为资源在外网,所以访问不了。解决方法,手动下载,并保存在指定位置.
下载链接在git上还有很多人的博客上都可以找到,为了防止失效,我又在自己的网盘里传了一个。
地址:https://pan.baidu.com/s/14KpU-BNuST6IwAFhWOosBA 提取码:s8zt

下载之后把缺少的包放在自动搜索的路径下,如各盘的根目录,在这里我把它放在了anaconda的路径下。
在…\anaconda\share路径下创建文件夹nltk_data,以punkt为例,把下载的数据解压,把punkt中的english.pickle 放在…\anaconda\share\nltk_data\tokenizers\punkt\PY3\english.pickle,就可以了。
有一个细节需要注意一下,在解压之后的文件夹中并没有包含名为PY3的文件夹,如果不自己创建一个的话,仍然会报错。
类似的问题也采用类似的解决方法。

如果以上的内容中出现了任何错误和不准确的地方,还请帮忙指出,谢谢。

4.结束

接下来的一段时间里,我会从最基础的内容开始NLP的学习,主要会记录一些基本的概念和NLP工具和模型在使用的过程中遇到的问题。那么我们下期再见。