中文词性标注
最近我想练习一下中文词性标注,所以找了一个数据集,人民日报PKU数据集。
数据集
数据集来自北大计算语言所,对1998年1月《人民日报》中的句子进行词性标注,语料格式为:
19980101-01-001-001/m 迈向/v 充满/v 希望/n 的/u 新/a 世纪/n ——/w 一九九八年/t 新年/t 讲话/n (/w 附/v 图片/n 1/m 张/q )/w
这个数据集中总共19484个句子提供训练测试。我对语料集做了特殊处理,去掉了不规范的不含’/'的标注,使得标注更加规范。
工具脚本
由于数据集内并不附赠脚本,所以我自己实现了一个工具脚本tool.py
tool.py
'''
tool.py
This is a tool for scoring posTag algorithm.
Just scoring an algorithm with:
> driver(trainLines, testLines, trainFunction, posTagFunction):
And this tool will print a report of accuracy.
Note: There are 19484 sentences in data set 'data.txt'.
Zhang Zhiyuan ,EECS Peking Univ. 2017/02/23
'''
class dataType:
def __init__(self):
self.__fd = open('data.txt', 'r')
self.__total = 0
self.__correct = 0
def getTrainLine(self):
while True:
bufferLine = self.__fd.readline().strip()
if len(bufferLine) > 0:
return bufferLine
def getTestLine(self):
while True:
self.__buffer = self.__fd.readline().strip()
line = self.__buffer
for word in line.split():
line = line.replace(word, word.split('/')[0])
if len(line) > 0:
return line
def testLine(self, line):
lineList = line.split()
bufferList = self.__buffer.split()
l = len(lineList)
for i in range(l):
self.__total += 1
if lineList[i].split('/')[1] == bufferList[i].split('/')[1]:
self.__correct += 1
def report(self):
print('Accuracy = %.5f' % (self.__correct / self.__total))
def driver(trainLines, testLines, trainFunction, posTagFunction):
totalLines = 19484
if trainLines + testLines > totalLines:
print('Too many lines!')
return
data = dataType()
for i in range(trainLines):
line = data.getTrainLine()
trainFunction(line)
for i in range(testLines)
data.testLine(posTagFunction(data.getTestLine()))
data.report()
脚本使用方法如注释所示,只需要调用函数driver()即可,下面举个例子来说明工具脚本使用方法
import tool
def train(line):
line = line
def posTag(line):
return('19980131-04-013-027/m 才/d 发觉/v 已/d 迷失/v 了/u 来路/n 。/w')
tool.driver(19483, 1, train, posTag)
请注意这个版本并不做实际计算,只是示意了训练函数和分词函数如何测试,而分词函数只是输来自数据集的答案,那么脚本会输出成绩:
Accuracy = 1.00000
如果修改训练句子数量为19484,那么因为用光了数据集,会输出:
Too many lines!
这些工具用面向对象风格实现,并封装在tool.py,以后测试不同算法只需要调用tool即可。如果有自然语言处理领域的爱好者学习者,可以自行下载数据集,并且把我的脚本拿去用使用。
朴素版本示例
最朴素的想法,对于一个词,给出最常见的标注方法。实现如下,做一个测试。
naive.py
import tool
dic = {}
def train(line):
for wordTag in line.split():
word, tag = wordTag.split('/')
if word in dic:
if tag in dic[word]:
dic[word][tag] += 1
else:
dic[word][tag] = 1
else:
dic[word] = {tag: 1}
def posTag(line):
lineList = line.split()
l = len(lineList)
for i in range(l):
word = lineList[i]
if word in dic:
bestTag = ''
bestTagFreq = 0
for tag in dic[word]:
if dic[word][tag] > bestTagFreq:
bestTagFreq = dic[word][tag]
bestTag = tag
lineList[i] = lineList[i] + '/' + bestTag
else:
lineList[i] = lineList[i] + '/' + 'unknow'
return(' '.join(lineList))
tool.driver(10000, 5000, train, posTag)
测试结果也不错,说明汉语中大部分词词性是很固定的,所以统计表词性可以直接获得不低的成绩。
Accuracy = 0.86114
做好了准备工作,可以开始学习中文词性标注,实现其他脚本了~