学习整理---中文分词

首先,谈一下这个概念是怎么走进我的脑袋的。要解决的问题是,土木专业有一些专业学术的文档需要根据一些特殊的实体进行标注,以前都是一些老师傅或者前辈人工进行工作,这样费人费力,并且人非圣贤孰能无过。所以,我们作为计算机一员,伸出了橄榄枝,希望通过计算机最大程度地正确快速进行实体标注。一开始,需求提出,我们就开始寻找匹配算法,网络资源虽然很多,但是并不知道怎么去查找。过程不细说,之后我莫名地就进入了CRF算法的了解与学习中。

CRF的使用场景:
假设你有许多小明同学一天内不同时段的照片,从小明提裤子起床到脱裤子睡觉各个时间段都有(小明是照片控!)。现在的任务是对这些照片进行分类。比如有的照片是吃饭,那就给它打上吃饭的标签;有的照片是跑步时拍的,那就打上跑步的标签;有的照片是开会时拍的,那就打上开会的标签。问题来了,你准备怎么干?一个简单直观的办法就是,不管这些照片之间的时间顺序,想办法训练出一个多元分类器。就是用一些打好标签的照片作为训练数据,训练出一个模型,直接根据照片的特征来分类。例如,如果照片是早上6:00拍的,且画面是黑暗的,那就给它打上睡觉的标签;如果照片上有车,那就给它打上开车的标签。这样可行吗?乍一看可以!但实际上,由于我们忽略了这些照片之间的时间顺序这一重要信息,或者说,照片之间的一些联系。我们的分类器会有缺陷的。举个例子,假如有一张小明闭着嘴的照片,怎么分类?显然难以直接判断,需要参考闭嘴之前的照片,如果之前的照片显示小明在吃饭,那这个闭嘴的照片很可能是小明在咀嚼食物准备下咽,可以给它打上吃饭的标签;如果之前的照片显示小明在唱歌,那这个闭嘴的照片很可能是小明唱歌瞬间的抓拍,可以给它打上唱歌的标签。所以,为了让我们的分类器能够有更好的表现,在为一张照片分类时,我们必须将与它相邻的照片的标签信息考虑进来。这——就是条件随机场(CRF)大显身手的地方!
(注:示例摘自:https://www.zhihu.com/question/35866596/answer/139485548

分析:先补充一下,我们整个设计过程中拥有的输入,一份需要标注的doc文档;一份xlsx格式的实体库。那么,结合示例和我们拥有的输入分析,CRF算法是需要一个训练模型的,也就是说要使用CRF算法实现分词,必须有一个训练模型作为输入,这个训练模型说的通俗点,就是经过可以确定的一些相互关系实现了分词的文档。但是我们的输入,与训练模型概念相匹配的就是那个xlsx格式的实体库,但是这个实体库只是一些没有相互关系的词组,是一个个逻辑上没有联系的个体,所以我们无法将它作为训练模型。

小结一下:讲了这么多,是因为想说明,从实现分词的角度上,CRF这个基于统计以及机器学习的分词方法,或许在准确度或者更多的方面要优于其他算法。但是我们要追求,对症下药。

下面描述一下网上我最接收的中文分词算法的分类
中文分词算法大概分为三大类,第一类是基于字符串匹配,即扫描字符串,如果发现字符串的子串和词典中的词相同,就算匹配,比如机械分词方法。这类分词通常会加入一些启发式规则,比如“正向/反向最大匹配”,“长词优先”等。第二类是基于统计以及机器学习的分词方法,它们基于人工标注的词性和统计特征,对中文进行建模,即根据观测到的数据(标注好的语料)对模型参数进行训练,在分词阶段再通过模型计算各种分词出现的概率,将概率最大的分词结果作为最终结果。常见的序列标注模型有HMM和CRF。这类分词算法能很好处理歧义和未登录词问题,效果比前一类效果好,但是需要大量的人工标注数据,以及较慢的分词速度。第三类是通过让计算机模拟人对句子的理解,达到识别词的效果,由于汉语语义的复杂性,难以将各种语言信息组织成机器能够识别的形式,目前这种分词系统还处于试验阶段。

由此可以看来,问题的解决办法趋向于使用机械分词的算法,即这中间最简单的正逆向匹配算法。这个网上也有各种语言的实现过程,异曲同工。

正向最大匹配算法(MM):按照人得而自然阅读顺序从左往右对一段话甚至文章进行词库匹配切分。
设MaxLen为最大词长,D为分词词典
(1)从待切分语料中按正向取长度为MaxLen的字符串str,令Len =MaxLen;
(2)将str与D中的词语互相匹配;
(3)if匹配成功,将指针向前移Len个汉字,并返回到(1);
(4)if 不成功:
    if( Len>1):
      Len = Len-1;
      从待切分语料中取长度为Len的字符串str,并返回(2);
    else:
      得到单个汉字,指针向前移一个汉字,并返回(1)
逆向最大匹配算法(RMM):主要原理与正向最大匹配算法一致,只是切分方向相反,从文章的尾部开始匹配。
(注:这不是我总结的_,来源也是一篇博客,看的多了,源地址一时找不到了...)

下面放出我的实现代码
match_result.py(正向匹配)

# -*- coding: utf-8 -*-


import xlrd # 处理xlsx文件
import codecs
from win32com import client # 处理word文档
import sys


# 打开xlsx文件
def open_excel(file_name):
    try:
        data = xlrd.open_workbook(file_name)
        print("[data]:", data)
        return data
    except (Exception, e):
        print(e)
    return False


# 解析xlsx文件中的内容
def excel_table_byindex(file_name, colnameindex=0, by_index=0):
    try:
        data = open_excel(file_name)
    except:
        return False
    if not data:
        return False
    table = data.sheets()[by_index]
    #print("[table]:", table)
    nrows = table.nrows # 行数
    print("[nrows]:", nrows)
    colnames = table.row_values(colnameindex) # 第一行数据(表头)
    #print("[colnames]:", colnames)
    ret_list = []
    for rownum in range(1, nrows):  # 对于表中的一行进行操作
        row = table.row_values(rownum)  # 一行的数据
        max_len = 0
        for item in row:
            item_no_blank = item.strip()
            if len(item_no_blank) > max_len:
                max_len = len(item_no_blank)
            ret_list.append(item_no_blank)
    return ret_list,max_len


# 进行匹配
# 这里有个坑解决了好长时间,temp.txt是本目录下的,但是win32这个模块在使用的时候必须
# 要写全路径,不然报错:File "<COMObject <unknown>>", line 8, in Open
def match_result(input_file, output_file, word_dict, max_len):
    word = client.Dispatch('Word.Application')
    input_data = word.Documents.Open(input_file)
    input_data.SaveAs(r"C:\Users\Maria\Desktop\研究生资料\正向匹配\temp.txt", 4)
    temp_file = open("temp.txt", "r")
    txt_content = temp_file.read()
    data_len = len(txt_content)
    temp_file.close()
    input_data.Close()
    word.Quit()
    word_list = ""
    cur = 0
    while cur < data_len:
        data = None
        for data in range(max_len, 0, -1):
            if txt_content[cur: cur+data] in word_dict:
                word_list += txt_content[cur: cur+data] + "/"
                break
        cur += data
    output_data = open(output_file, "w")
    output_data.write(word_list)
    output_data.close()


if __name__ == '__main__':
    if len(sys.argv) != 3:
        print("Usage:Need two arguments!")
        sys.exit()
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data,max_len = excel_table_byindex("实体库.xlsx")
    #print(data)
    match_result(input_file, output_file, data, max_len)


逆向匹配
reverse_match_result.py

def reverse_match_result(input_file, output_file, word_dict, max_len):
    word = client.Dispatch('Word.Application')
    input_data = word.Documents.Open(input_file)
    input_data.SaveAs(r"C:\Users\Maria\Desktop\研究生资料\正向匹配\temp.txt", 4)
    temp_file = open("temp.txt", "r")
    txt_content = temp_file.read()
    data_len = len(txt_content)
    temp_file.close()
    input_data.Close()
    word.Quit()
    word_list = []
    cur = data_len
    while cur > 0:
        data = None
        if max_len > cur:
            max_len = cur
        for data in range(max_len, 0, -1):
            if txt_content[cur-data: cur] in word_dict:
                word_list.insert(0, str(txt_content[cur-data: cur]) + "/")
                break
        cur -= data
    output_data = open(output_file, "w")
    output_data.write("".join(word_list))
    output_data.close()

注:两点,1.正逆向匹配算法简单说起来就是字符串匹配,一种很机械化地分词方式,所以只是在于编写代码的语言相应代码的多少和使用的数据结构上有的选,或者一些程度上的优化。2.代码实现过程中可能有些繁琐,希望提出意见。

最后,虽然CRF算法直接使用有点不太合适,但是,优先在待分析字符串中识别和切分出一些带有明显特征的词,以这些词作为断点,可将原字符串分为较小的串再来进机械分词,从而减少匹配的错误率,这也是一个不错的选择,只不过这样的话,我们就需要有一个这个行业的训练模型了。

这是CRF算法中可以下载的一些训练模型(我自己的腾讯云服务器没有实现训练,可能是内存的关系吧,对于CRF的使用,网上有很多教程,搜索即可。)
下载中文分词语料库地址:http://sighan.cs.uchicago.edu/bakeoff2005/,语料来自:
台湾中央研究院(Academia Sinica)、香港城市大学(City University of Hong Kong)、北京大学(Peking University)及微软亚洲研究院(Microsoft Research)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容