中文分词总结

简介

方法可以归纳为 “规则分词”、“统计分词” 和 “混合分词(规则 + 统计)”

规则分词主要是通过人工设立词库,按照一定方式进行匹配切分,但对新词很难进行处理

统计机器学习兴起后,能够较好应对新词发现,但过于依赖语料的质量。

规则分词

通过维护词典,切分语句时,将语句的每个字符串与词表的词进行逐一匹配,找到则切分,否则不予切分

主要有正向最大匹配法、逆向最大匹配法以及双向中最大匹配法

正向最大匹配法(MM 法)

基本思想:假定分词词典中最长词有 i 个汉字字符,则当前要处理的字串的前 i 个字作为匹配字段

若匹配成功,匹配字段作为一个词切分出去

若匹配失败,将匹配字段的最前一个字去掉,重新匹配

知道匹配成功或者匹配字段长度为 0

如 “南京市长江大桥”,词典中存在 “南京市长” 和 “长江大桥”,且最长词的长度为 5,则会分为 “南京市长”、“江”、“大桥”。这显然不是我们想要的

# 正向最大匹配
class MM(object):
    def __init__(self, dic_path):
        self.dictionary = set()
        self.maximum = 0
        with open(dic_path, 'r', encoding='utf8') as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                self.dictionary.add(line)
                if len(line) > self.maximum:
                    self.maximum = len(line)
                    
    def cut(self, text):
        result = []
        index = 0
        length = len(text)
        while index < length:
            word = None
            for size in range(self.maximum, 0, -1):
                if index + size > length:
                    continue
                piece = text[index:(index + size)]
                if piece in self.dictionary:
                    word = piece
                    result.append(word)
                    index += size
                    break
            if word is None:
                result.append(text[index])
                index += 1
        return result

def main():
    text = "南京市长江大桥"
    tokenizer = MM('imm_dic.utf8')
    print(tokenizer.cut(text))
main()

输出 [‘南京市长’, ‘江’, ‘大桥’]

逆向最大匹配法(RMM 法)

与 MM 法类似,每次从文档的末端开始匹配,匹配失败去掉最后面一个字。

相应地,分词词典是逆序词典,文档也要先进行倒排处理。

汉语中偏正结构较多,所以从后向前匹配,可以适当的提高精度。

统计结果表明,单纯使用 MM 错误率为 1/169,单纯使用 RMM 错误率为 1/245。

# 逆向最大匹配
class RMM(object):
    def __init__(self, dic_path):
        self.dictionary = set()
        self.maximum = 0
        with open(dic_path, 'r', encoding='utf8') as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                self.dictionary.add(line)
                if len(line) > self.maximum:
                    self.maximum = len(line)
    def cut(self, text):
        result = []
        index = len(text)
        while index > 0:
            word = None
            for size in range(self.maximum, 0, -1):
                if index - size < 0:
                    continue
                piece = text[(index - size):index]
                if piece in self.dictionary:
                    word = piece
                    result.append(word)
                    index -= size
                    break
            if word is None:
                result.append(text[index-1])
                index -= 1
        return result[::-1]

def main():
    text = "南京市长江大桥"
    tokenizer = RMM('imm_dic.utf8')
    print(tokenizer.cut(text))
main()

输出 [‘南京市’, ‘长江大桥’]

双向最大匹配法

将 MM 和 RMM 分词结果进行比较,按照最大匹配原则,选取词数切分最少的作为结果。

SunM.S.(1995) 表明,只有 1 % 的句子,使用 MM 和 RMM 都不对。

双向最大匹配法在实用中文信息处理系统中广泛使用

# 双向最大匹配法
def main():
    text = "南京市长江大桥"
    tokenizer1 = MM('imm_dic.utf8')
    tokenizer2 = RMM('imm_dic.utf8')
    res1 = tokenizer1.cut(text)
    res2 = tokenizer2.cut(text)
    if len(res1) < len(res2):
        print(res1)
    else:
        print(res2)
main()

输出 [‘南京市’, ‘长江大桥’]

统计分词

主要思想:词看作各个字组成,如果相连的字在不同的文本出现的次数越多,就证明这很可能就是一个词。

利用字与字相邻出现的频率反映成词的可靠度,当高于一个临界值时,就认为可能构成一个词语。

  1. 建立语言模型
  2. 对句子进行单词划分,然后对划分结果进行概率计算,获得概率最大的分词方式。这里会用到隐马尔可夫、条件随机场等。

【待完成:HMM 模型】

混合分词

最常用的方式就是先基于词典的方式进行分词,然后再用统计分词方法进行辅助。Jieba 分词工具便是基于这种方法

Jieba分词

基于规则和统计两类方法

首先基于前缀词典进行词图扫描,构建包含全部可能分词结果的有向无环图。基于标注语料,使用动态规划方法可以找出最大概率模型。

对于未登录词,Jieba 使用了基于汉字成词的 HMM 模型,采用了 Viterbi 算法进行推导。

三种分词模式:

  1. 精确模式:试图将句子最精确切开,适合文本分析
  2. 全模式:所有可以成词的词语都扫描出来,速度很快,但是不能解决起义
  3. 搜索引擎模式:在精确模式基础上,对长词再次切分,提高召回率,适合搜索引擎分词。
import jieba
sent = '中文分词是文本处理不可或缺的一步!'
seg_list = jieba.cut(sent, cut_all=True)
print('全模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent, cut_all=False)
print('精确模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent)
print("默认精确模式:", '/ '.join(seg_list))

seg_list = jieba.cut_for_search(sent)
print('搜索引擎模式:', '/ '.join(seg_list))import jieba
sent = '中文分词是文本处理不可或缺的一步!'
seg_list = jieba.cut(sent, cut_all=True)
print('全模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent, cut_all=False)
print('精确模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent)
print("默认精确模式:", '/ '.join(seg_list))

seg_list = jieba.cut_for_search(sent)
print('搜索引擎模式:', '/ '.join(seg_list))

高频词提取

高频词提取其实就是 TF (Term Frequency) 策略

  1. get_content
  2. cut -> split_words 忽略一些词
  3. get_TF 排序 字典计数 get 方法
import numpy as np
import glob
import jieba
def get_content(path):
    with open(path, 'r', encoding='utf8', errors='ignore') as f:
        content = ''
        for l in f:
            l = l.strip()
            content += l
        return content
def get_TF(words, topK=10):
    tf_dic = {}
    for w in words:
        tf_dic[w] = tf_dic.get(w, 0) + 1  # 获取 w 的计算,没有就置为 0
    return sorted(tf_dic.items(), key=lambda x:x[1], reverse=True)[:topK]
def stop_words(path):  # 跳过的词,返回列表
    with open(path, encoding='utf8') as f:
        return [l.strip() for l in f]
def cut(content):
    split_words = [x for x in jieba.cut(content) if x not in [',', '。','、'] and len(x)>1]  #这里可以用 stop_words
    return split_words
def main():
    files = glob.glob('news.txt') #可以读多个文件
    corpus = [get_content(x) for x in files]
    
    sample_inx = np.random.randint(0, len(corpus)) #随机选择一个文件,不过这里就使用一个
    split_words = cut(corpus[sample_inx])
    print('样本的topK(10)词:'+str(get_TF(split_words)))

注意:np.random.randint是左闭右开区间,而random.randint是左闭右闭区间

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值