自然语言处理——中英文分词

本文详细介绍了中文和英文的分词方法,包括机械分词法中的正向最大匹配、逆向最大匹配和双向最大匹配,以及统计分词法中的语料统计法和序列标注法。以jieba分词工具为例,展示了精确模式、全模式和搜索引擎模式的使用,并探讨了如何处理未登录词。此外,还讨论了自定义词典在提高分词效果中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

英文分词

中文分词

机械分词法

正向最大匹配法

逆向最大匹配法

双向最大匹配法

统计分词法

语料统计法

序列标注法


英文分词

  • 英文原文: it is a good day!
  • 分词结果: it , is , a , good , day , !

通过上面的英文分词例子,可以发现英文文本词与词之间有空格或者标点符号,如果想要对这种普通的英文文本进行分词的话是不需要什么算法支撑,直接通过空格或者标点来将文本进行分开就可以完成英文分词。

如果要对多个英文文本分词,要求同时以 , , . , ? , ! , 五个符号分词。为了方便调用,我们将代码写成一个函数。首先对原文本以其中一个规则切分后,再对分好后的文本进行下一个规则的切分,再对分好的文本进行切分,直到按 5 个规则切分完成,最后将切分好的词添加进 tokenized_text 并返回。这里还是把 .split() 方法当作拆分的核心:

def tokenize_english_text(text):
    # 首先,我们按照标点来分句
    # 先建立一个空集用来,用来将分好的词添加到里面作为函数的返回值
    tokenized_text = []
    # 一个 text 中可能不止一个内容,我们对每个文本单独处理并存放在各自的分词结果中。
    for data in text:
        # 建立一个空集来存储每一个文本自己的分词结果,每对 data 一次操作我们都归零这个集合
        tokenized_data = []
        # 以 '.'分割整个句子,对分割后的每一小快 s:
        for s in data.split('.'):
            # 将's'以 '?'分割,分割后的每一小快 s2:
            for s1 in s.split('?'):
                # 同样的道理分割 s2,
                for s2 in s1.split('!'):
                    # 同理
                    for s3 in s2.split(','):
                        # 将 s3 以空格分割,然后将结果添加到 tokenized_data 当中
                        tokenized_data.extend(
                            s4 for s4 in s3.split(' ') if s4 != '')
                        # 括号内的部分拆开理解
                        # for s4 in s3.split(' '):
                        #    if s4!='':  这一步是去除空字符''。注意与' ' 的区别。
        # 将每个 tokenized_data 分别添加到 tokenized_text 当中
        tokenized_text.append(tokenized_data)

    return tokenized_text

写好函数后,我们来调用函数对英文文本分词。为了直观展示,我们自定义多个文本,模拟英文应用中的多个文本:

a = ['i am a boy?i am a boy ! i am a boy,i', 'god is a girl', 'i love you!']
result = tokenize_english_text(a)
result

# 输出结果如下
# [['i', 'am', 'a', 'boy', 'i', 'am', 'a', 'boy', 'i', 'am', 'a', 'boy', 'i'],
# ['god', 'is', 'a', 'girl'],
# ['i', 'love', 'you']]

 

中文分词

  • 中文原文: 今天是个好日子。
  • 分词结果: 今天 | 是 | 个 | 好 | 日子 。

在中文中,文本是由连续的字序列构成,词和词之间没有天然的分隔符。不同分词方法的结果会影响到词性,句法等问题。分词作为一个方法,如果运用场景不同,要求不同,最终对任务达到的效果也不同。可以说中文分词相对英文分词有很大的困难。

机械分词法

机械分词方法又叫做基于规则的分词方法:这种分词方法按照一定的规则将待处理的字符串与一个词表词典中的词进行逐一匹配,若在词典中找到某个字符串,则切分,否则不切分。机械分词方法按照匹配规则的方式,又可以分为:正向最大匹配法,逆向最大匹配法和双向匹配法三种。

正向最大匹配法

正向最大匹配法(Maximum Match Method,MM 法)是指从左向右按最大原则与词典里面的词进行匹配。假设词典中最长词是 𝑚m 个字,那么从待切分文本的最左边取 𝑚m 个字符与词典进行匹配,如果匹配成功,则分词。如果匹配不成功,那么取 𝑚−1m−1 个字符与词典匹配,一直取直到成功匹配为止。

首先我们先给定文本和字典:

# 文本
text = '我们是共产主义的接班人'

# 词典
dic = ('我们', '是', '共产主义', '的', '接班', '人', '你', '我', '社会', '主义')

然后我们需要遍历词典来求出最长词的长度:

# 初始最长词长度为 0
max_len_word0 = 0
for key in dic:
    # 若当前词长度大于 max_len_word,则将 len(key)值赋值给 max_len_word
    if len(key) > max_len_word0:
        max_len_word0 = len(key)

下面是通过循环来完成 MM 法:

sent = text
words = []   # 建立一个空数组来存放分词结果:
max_len_word = max_len_word0
# 判断 text 的长度是否大于 0,如果大于 0 则进行下面的循环
while len(sent) > 0:
    # 初始化想要取的字符串长度
    # 按照最长词长度初始化
    word_len = max_len_word
    # 对每个字符串可能会有(max_len_word)次循环
    for i in range(0, max_len_word):
        # 令 word 等于 text 的前 word_len 个字符
        word = sent[0:word_len]
        # 为了便于观察过程,我们打印一下当前分割结果
        print('用 【', word, '】 进行匹配')
        # 判断 word 是否在词典 dic 当中
        # 如果不在词典当中
        if word not in dic:
            # 则以 word_len - 1
            word_len -= 1
            # 清空 word
            word = []
        # 如果 word 在词典当中
        else:
            # 更新 text 串起始位置
            sent = sent[word_len:]
            # 为了方便观察过程,我们打印一下当前结果
            print('【{}】 匹配成功,添加进 words 当中'.format(word))
            print('-'*50)
            # 把匹配成功的word添加进上面创建好的words当中
            words.append(word)
            # 清空word
            word = []

# 输出结果如下
# ['我们', '是', '共产主义', '的', '接班', '人']

逆向最大匹配法

逆向最大匹配法( Reverse Maximum Match Method, RMM 法)的原理与正向法基本相同,唯一不同的就是切分的方向与 MM 法相反。逆向法从文本末端开始匹配,每次用末端的最长词长度个字符进行匹配。

双向最大匹配法

双向最大匹配法(Bi-direction Matching Method ,BMM)则是将正向匹配法得到的分词结果与逆向匹配法得到的分词结果进行比较,然后按照最大匹配原则,选取次数切分最少的作为结果。

统计分词法

上面主要讲述了基于字典的分词方法,可以发现基于的字典的方法实现比较简单,而且性能也还不错。但是其有一个缺点,那就是不能切分未登录词(即没有被收录在分词词表中但必须切分出来的词,包括各类专有名词(人名、地名、企业名等)、缩写词、新增词汇等等),也就是不能切分字典里面没有的词。为解决这一问题,于是有学者提出了基于统计的分词方法,包括语料统计法和序列标注法。

语料统计法

对于语料统计方法可以这样理解:我们已经有一个由很多个文本组成的的语料库 D ,假设现在对一个句子【我有一个苹果】进行分词。其中两个相连的字 【苹】【果】在不同的文本中连续出现的次数越多,就说明这两个相连字很可能构成一个词【苹果】。与此同时 【个】【苹】 这两个相连的词在别的文本中连续出现的次数很少,就说明这两个相连的字不太可能构成一个词【个苹】。所以,我们就可以利用这个统计规则来反应字与字成词的可信度。当字连续组合的概率高过一个临界值时,就认为该组合构成了一个词语。

序列标注法

序列标注方法则将中文分词看做是一个序列标注问题。首先,规定每个字在一个词语当中有着 4 个不同的位置,词首 B,词中 M,词尾 E,单字成词 S。我们通过给一句话中的每个字标记上述的属性,在训练时,输入中文句子和对应的标注序列,训练完成得到一个模型。在测试时,输入中文句子,通过模型运算得到一个标注序列。然后通过标注序列来进行切分句子。目前在实际应用中,jieba 分词是使用率很高的一款工具。

在使用 jieba 进行分词时,有三种模式可选:

1、全模式

import jieba
string = '我来到中国科学院大学上大学'
seg_list = jieba.cut(string, cut_all=True)
'| '.join(seg_list)

# 输出结果如下
# '我| 来到| 中国| 中国科学院| 科学| 科学院| 学院| 大学| 学上| 大学'

2、精确模式

import jieba
string = '我来到中国科学院大学上大学'
seg_list = jieba.cut(string, cut_all=False)
'| '.join(seg_list)

# 输出结果如下
# '我| 来到| 中国科学院| 大学| 上| 大学'

3、搜索引擎模式

import jieba
string = '我来到中国科学院大学上大学'
seg_list = jieba.cut_for_search(string)
'| '.join(seg_list)

# 输出结果如下
# '我| 来到| 中国| 科学| 学院| 科学院| 中国科学院| 大学| 上| 大学'

jieba 在某些特定的情况下分词,可能表现不是很好。比如一篇非常专业的计算机技术论文,含有一些特定领域的专有名词。不过,为了解决此类问题, jieba 允许用户自己添加该领域的自定义词典,我们可以提前把这些词加进自定义词典当中,来增加分词的效果。调用的方法是:jieba.load_userdic()

除了使用 jieba.load_userdic() 函数在分词开始前加载自定义词典之外,还有两种方法在可以在程序中动态修改词典:

  • 使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中动态修改词典。

  • 使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡心curry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值