文本挖掘——中文分词学习

jieba库头歌学习总结

基于jieba的中文分词

jieba的特点

  • 社区活跃

  • 功能丰富

  • 提供多种编程语言实现

  • 使用简单

jieba分词原理

结合了基于规则和基于统计这两类方法。首先基于前缀词典进行词图扫描,前缀词典是指词典中的词按照前缀包含的顺序排列。如果将词看作节点,词和词之间的分词符看作边,那么一种分词方案则对应着从第一个字到最后一个字的一条分词路径。

jieba分词的三种模式

精确模式:试图将句子最精确地切开,适合文本分析;

jieba.cut(sentence, cut_all=False)

全模式:把句子中所有可以成词的词语都扫描出来,速度非常快,但是不能解决歧义;

jieba.cut(sentence, cut_all=True)

搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

jieba.cut_for_search(sentence)

词频统计算法

import jieba
text= input()
words = jieba.lcut(text)  
data={} # 词典
for word in words:
    if len(word) < 2:  # 判断word是否大于2个字,构成一个词
        continue
    if word in data:
        data[word] += 1  # word再次出现
    else:
        data[word] = 1  # word首次出现
data = sorted(data.items(), key=lambda x: x[1], reverse=True)  # 排序
print(data[:3],end="")

规则分词法

正向最大匹配法(MM法)

算法过程

从左向右取待切分汉语句的 m 个字符作为匹配字段, m 是机器词典中最长词条的字符数;查找机器词典并进行匹配。匹配成功则将匹配字段作为一个词切分出来,匹配失败则将匹配字段的最后一个字去掉,剩下的字符串作为新的匹配字段,进行再匹配,一直重复上述过程直到切分出所有词。

文字示例

我们现有的分词词典中最长的长度为5,词典中有南京市、长江、大桥三词,现采用 MM 法对句子南京市长江大桥进行分词,那么首先从句子中取出前5个字南京市长江,发现词典中没有该词,于是缩小长度,取前4个字南京市长,发现词典中还是没有该词,于是继续缩小长度,取前3个字南京市,词典中存在该词,于是该词被确认切分。再将剩下的长江大桥按照同样方式进行切分,得到长江和大桥,最终切分为南京市/长江/大桥3个词。

逆向最大匹配法(RMM法)

算法过程

逆向最大匹配( RMM 法)法的基本思想与 MM 法相同,不同的是分词切分的方向与 MM 法相反。逆向最大匹配法从右到左来进行切分。每次取最右边(末端)的 m 个字符作为匹配字段, 若匹配失败,则去掉匹配字段最左边(前面)的一个字,继续匹配。

文字示例

南京市长江大桥,按照逆向最大匹配,分词词典中最长词条的字符数长度为5,分词词典中有南京市长和长江大桥两词,现采用 RMM 法对句子南京市长江大桥进行分词,那么首先从句子中从右到左取出前5个字市长江大桥,发现词典中没有该词,于是缩小长度,取前4个字长江大桥,词典中存在该词,于是该词被确认切分。再将剩下的南京市按照同样方式进行切分,得到南京市,最终切分为南京市/长江大桥2个词。当然,如此切分并不代表完全正确,可能有个叫江大桥的南京市长也说不定。

双向最大匹配法

算法过程

  • 比较正向最大匹配和逆向最大匹配结果;

  • 如果分词数量结果不同,那么取分词数量较少的那个;

  • 在分词数量结果相同的情况下,如果分词结果相同,则可以返回任何一个;如果分词结果不同,则返回单字数比较少的那个。

文字示例

北京大学生前来应聘这个句子,如果通过正向最大匹配算法得到的结果为北京大学 / 生前 / 来 / 应聘,其中分词数量为4,单字数为 1;而通过逆向最大匹配算法所得到的结果为北京/ 大学生/ 前来 / 应聘,其中分词数量为4,单字数为0。则根据双向最大匹配算法,逆向匹配单字数少,因此返回逆向匹配的结果。

代码实现

class BiMM():
    def __init__(self):
        self.window_size = 3  # 字典中最长词数

    def MMseg(self, text, dict): # 正向最大匹配算法
        result = []
        index = 0
        text_length = len(text)
        while text_length > index:
            for size in range(self.window_size + index, index, -1):
                piece = text[index:size]
                if piece in dict:
                    index = size - 1
                    break
            index += 1
            result.append(piece)
        return result

    def RMMseg(self, text, dict): # 逆向最大匹配算法
        result = []
        index = len(text)
        while index > 0:
            for size in range(index - self.window_size, index):
                piece = text[size:index]
                if piece in dict:
                    index = size + 1
                    break
            index = index - 1
            result.append(piece)
        result.reverse()
        return result

    def main(self, text, r1, r2):
    # 任务:完成双向最大匹配算法的代码描述
    # 分词数量若不同,则选取少的那个
        if len(r1) < len(r2):
            print(r1)
        elif len(r1) > len(r2):
            print(r2)
        # 分词数量若相同
        else:
            # 判断分词元素是否一致
            if set(sorted(r1)) != set(sorted(r2)):  # 若不一致,判断单字分词个数
                count1 = sum(1 for i in r1 if len(i) == 1)
                count2 = sum(1 for j in r2 if len(j) == 1)
                print(r1) if count1 < count2 else print(r2)
            else:
                print(r1)

词性标注

什么是词性标注?

词性标注(Part-of-Speech Tagging,简称POS Tagging)是自然语言处理(NLP)中的一种技术,它将每个单词标注为相应的词性(如名词、动词、形容词等),以明确其在句子中的语法功能。

词性标注的目的在于为文本的进一步处理奠定基础,帮助理解句子的结构、解析语法,或者为机器翻译、文本摘要等高级任务提供信息。

调用方法

import jieba.posseg as peg  # jieba库中词性分析模块
peg.cut('sentence')

运行逻辑

  1. 首先基于正则表达式进行汉字判断;

  2. 若符合汉字正则表达式,则基于前缀词典构建有向无环图,再基于有向无环图计算最大概率路径,同时在前缀词典中找出它所分出的词性,若在词典中未找到,则赋予词性为 x (代表未知)。当然,若在这个过程中,设置使用 HMM ,且待标注词为未登录词,则会通过 HMM 方式进行词性标注;

  3. 若不符合上面的正则表达式,那么将继续通过正则表达式进行类型判断,分别赋予 x 、 m (数词)和 eng (英文)。

代码示例

import jieba.posseg as peg  # jieba库中词性分析模块

text = input()
def cut_words():
    words = psg.cut(text)
    for word, flag in words:
        print(word + "/" + flag, end=" ")

命名实体识别

什么是命名实体识别?

命名实体识别(Named Entity Recognition,简称NER)是自然语言处理(NLP)中的一项核心任务,旨在从文本中识别出具有特定意义的实体,并将它们分类为预定义的类别。

NER的目标是在给定的文本中找出这些实体,并将它们标注为相应的类别。例如,句子“乔布斯于2004年创立了苹果公司”中的“乔布斯”是人名,“苹果公司”是组织名,“2004年”是时间。

调用方法

Python的第三方库HanLP——一系列模型与算法组成的工具包,目标是普及自然语言处理在生产环境中的应用。

安装方法

pip install pyhanlp
from pyhanlp import HanLP # 使用前导入 HanLP工具

识别逻辑

基于HMM 算法对人名进行识别

代码示例

from pyhanlp import HanLP
text = input()
# 任务:完成对 text 文本的人名识别并输出结果
segment = HanLP.newSegment().enableNameRecognize(True); # 构建人名识别器
# segment = HanLP.newSegment().enablePlaceRecognize(True); # 构建地名识别器
result = segment.seg(text)
print(result)

<think>嗯,我现在需要完成这个BiMM类中的main方,实现双向最大匹配算。首先,我得理解双向最大匹配的原理。那双向最大匹配通常是同时使用正向最大匹配(MM)和逆向最大匹配(RMM),然后根据一定的规则选择其中一个结果作为最终分词结果。 根据代码框架,BiMM类已经实现了MMseg和RMMseg两个方,分别处理正向和逆向的分词。现在main方需要将两者的结果进行比较,并根据规则决定使用哪个结果。常见的规则可能有:选择分词数量较少的一个;或者如果数量相同,选择单字较少的;如果还相同,可能选择逆向的结果或者其他方式。 那首先,我需要调用MMseg和RMMseg方得到两个结果r1和r2。不过,原题中的main函数的参数是text, r1, r2,可能这里的r1和r2是已经传入的正向和逆向的结果?或者可能题目中的参数可能有误?或者可能原题框架中的main函数需要自己调用MMseg和RMMseg? 看原题中的代码,main方的参数是text, r1, r2。这可能需要进一步确认。但可能题目中的参数可能有误,可能应该让main方接收text和dict,然后自己调用MMseg和RMMseg得到结果。不过根据用户提供的代码框架,main的参数是text, r1, r2,那可能r1和r2是两种分词结果,需要进行比较。或者可能题目中存在笔误,正确的参数可能应为字典或其他? 这时候可能需要结合题目上下文来理解。原题的任务是完成双向最大匹配的代码,所以可能原题中的main函数需要调用MMseg和RMMseg得到结果,然后比较这两个结果,并返回最终的分词结果。但原题给出的main的参数是text, r1, r2,这看起来可能有问题,因为通常双向匹配需要字典来进行分词。或者可能原题的参数中的r1和r2是其他参数,比如字典? 或者,可能是题目中的参数书写错误,可能应该传入text和dict,而不是r1和r2。这种情况下,正确的代码可能需要修改参数。例如,在main函数中应该调用MMseg和RMMseg,传入text和dict,然后比较两者的结果。 假设原题中的参数可能有误,或者需要用户自己调整。例如,正确的main函数应该接收text和字典,然后调用MMseg和RMMseg得到r1和r2。那现在的问题就是如何根据这两个结果进行选择。 根据双向最大匹配的规则,通常比较两个结果的词数,选择词数较少的。如果词数相同,则选择单字较少的那个。如果还是相同,可以任意选择其中一个,比如选逆向的结果。 所以,在main方中,需要先得到正向和逆向的分词结果,然后比较它们的长度。例如: r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) 然后比较len(r1)和len(r2)。如果len(r1) < len(r2),则选r1;反之选r2。如果相等,则比较单字的数量。比如统计每个结果中长度为1的词的数量,选择较少的那个。如果还相同,则选择逆向的结果。 现在原题中的main函数参数是text, r1, r2。这可能意味着用户传入的r1和r2是已经分好的结果,但可能题目中的参数有误。或者,可能原题中的main方需要接收text和字典,而r1和r2是内部调用的结果? 这种情况下,原题的代码框架可能有误。例如,正确的main函数应该接受text和字典作为参数,然后调用MMseg和RMMseg。比如: def main(self, text, dict): r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 比较逻辑... 但原题给出的main函数是def main(self, text, r1, r2):,这似乎不太合理。可能题目中的参数名有误,或者需要重新理解。比如,可能这里的r1和r2是字典或其他参数? 或者,可能题目中的代码存在笔误,正确的参数应为字典,而用户需要补全的代码部分需要调用MMseg和RMMseg,传入字典。例如: 在main函数内部,可能应该调用MMseg和RMMseg,而不是直接接收r1和r2作为参数。所以原题中的参数可能不正确,正确的参数可能应为text和dict。这样,用户需要补全的代码部分需要调用MMseg和RMMseg方,并将得到的r1和r2进行比较。 所以,可能原题中的main函数定义有误,正确的参数应该包括字典。例如: def main(self, text, dict): r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 比较逻辑... 但根据用户提供的代码框架,原题的main函数参数是text, r1, r2,可能用户需要在这里实现比较逻辑,但参数可能存在问题。这种情况下,可能需要根据题目要求,假设正确的参数应为text和dict,而r1和r2是内部调用的结果。或者可能题目中的r1和r2是其他参数? 现在这种情况下,可能存在题目中的代码框架错误,但用户需要根据现有框架完成代码。或者可能我误解了题目,需要再仔细看题目。 原题中的任务描述是:“完成双向最大匹配算的代码描述”,而给出的main函数框架的参数是text, r1, r2。这可能说明,r1和r2是正向和逆向的分词结果,所以main函数需要比较这两个结果,并返回最终的。例如,在测试代码中,可能已经调用了MMseg和RMMseg得到r1和r2,并传入main方进行比较。这种情况下,main函数的作用是接收两个分词结果,根据规则选择正确的。 但如果是这样的话,main函数的逻辑就是比较r1和r2,然后返回最终结果。但通常,双向最大匹配算是需要同时执行正向和逆向的分词,再进行比较。所以,这可能不符合常规做。或者可能题目中的参数名写错了,比如应该是text和dict,而不是r1和r2? 或者,可能题目中的r1和r2是两种不同的字典?比如,可能用户需要同时传入正向和逆向的词典?这不太可能。 现在,可能需要假设题目中的参数是text,字典,或者其他参数。但原题中的参数是text, r1, r2,这似乎有问题。 或者,可能原题中的参数是正确的,但r1和r2是其他参数?比如,是否是笔误,正确的参数名应为dict或其他? 这可能需要更多的信息,但用户提供的代码框架中的main函数的参数是text, r1, r2,所以可能需要按照这个框架来完成代码。但如何在这种情况下实现双向匹配? 比如,可能r1是正向分词的结果,r2是逆向分词的结果,然后main函数需要比较这两个结果,并返回最终的分词结果?但这样的话,main函数的参数是text, r1, r2,但text可能未被使用。这可能不太合理。 或者,可能参数中的r1和r2是其他参数,比如分割后的结果或者其他参数。此时可能需要重新审视问题。 另一种可能是,原题中的代码框架存在错误,正确的参数应该是text和dict,而用户需要补全的代码需要调用MMseg和RMMseg方,传入正确的参数。例如: 在main函数中,应该先调用MMseg和RMMseg得到两个结果,然后比较。因此,正确的参数应该是text和dict,而代码框架中的参数可能有误。但用户无修改参数,只能根据现有框架完成代码。 在这种情况下,可能用户需要根据现有的参数来推测正确的处理方式。例如,如果原题中的main函数参数text, r1, r2中的r1和r2可能并非参数,而是其他变量?或者可能代码中的参数书写有误? 在这种情况下,可能存在题目中的笔误,正确的main函数应该没有r1和r2作为参数,而是内部调用MMseg和RMMseg方,传入text和dict。例如: def main(self, text, dict): r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 比较逻辑... 假设这种情况下,用户需要补全的代码部分就是这样的逻辑。所以,在给定的代码框架中,参数可能应该是text和dict,但被错误地写成了text, r1, r2。这可能是一个笔误,需要用户自行纠正。 在这种情况下,用户需要将main函数的参数更正,并调用相应的分词。因此,在补全代码时,应该先调用MMseg和RMMseg得到r1和r2,然后进行比较。 现在,假设原题中的main函数的参数应为text和dict,那么正确的代码应该如下: 在main函数中: r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) 然后比较这两个结果: 如果r1的分词数目不等于r2的,则选择数目较少的;若数目相同,则比较单字数目,选择单字数目较少的;如果还相同,则返回逆向结果(r2)。 例如: if len(r1) != len(r2): return r1 if len(r1) < len(r2) else r2 else: count_r1 = sum(1 for word in r1 if len(word) == 1) count_r2 = sum(1 for word in r2 if len(word) == 1) if count_r1 != count_r2: return r1 if count_r1 < count_r2 else r2 else: # 根据规则选择逆向结果 return r2 或者可能需要根据具体规则,比如有的规则是当两种方结果数目相同时,选择单字数目少的;如果单字数目也相同,则返回逆向匹配结果。 因此,代码的逻辑大概是这样的。 但原题中的main函数的参数是text, r1, r2,这可能意味着r1和r2已经被计算好传入,这可能不符合常规逻辑。所以这可能意味着题目中的代码存在错误,需要用户忽略参数中的r1和r2,并在main函数内部调用MMseg和RMMseg方。 综上所述,我认为原题中的main函数的参数可能存在错误,正确的参数应为text和dict。因此,用户需要补全的代码应该是在main函数中调用MMseg和RMMseg,得到r1和r2,然后进行比较,并返回最终结果。 所以,补全后的main函数代码可能如下: def main(self, text, dict): r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 比较两个结果 if len(r1) != len(r2): return r1 if len(r1) < len(r2) else r2 else: count_r1 = sum(1 for word in r1 if len(word) == 1) count_r2 = sum(1 for word in r2 if len(word) == 1) if count_r1 != count_r2: return r1 if count_r1 < count_r2 else r2 else: # 如果单字数量也相同,返回逆向结果 return r2 但原题中的main函数的参数是text, r1, r2,而正确的参数应为text和dict。所以可能原题的参数是错误的,或者题目中的参数名可能被错误地写成r1和r2,而实际应为dict? 例如,可能正确的参数应为text和dict,而用户需要调用MMseg和RMMseg时传入dict。因此,原题中的main函数参数可能应该修改为text, dict。在这种情况下,补全的代码应该为: def main(self, text, dict): r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 比较逻辑... 因此,假设题目中的参数有误,正确的参数是text和dict,而不是r1和r2。在这种情况下,用户需要补全的代码部分应调用MMseg和RMMseg,传入字典参数,然后比较结果。 综上,我认为原题中的main函数参数可能存在错误,正确的参数应为text和dict。因此,补全的代码应该是在main函数内部调用MMseg和RMMseg,并将它们的返回结果进行比较,根据规则选择最终的分词结果。</think>以下是双向最大匹配算的实现步骤及代码: ```python class BiMM(): def __init__(self): self.window_size = 3 # 字典中最长词数 def MMseg(self, text, dict): # 正向最大匹配算 result = [] index = 0 text_length = len(text) while text_length > index: for size in range(self.window_size + index, index, -1): piece = text[index:size] if piece in dict: index = size - 1 break index += 1 result.append(piece) return result def RMMseg(self, text, dict): # 逆向最大匹配算 result = [] index = len(text) while index > 0: for size in range(index - self.window_size, index): piece = text[size:index] if piece in dict: index = size + 1 break index = index - 1 result.append(piece) result.reverse() return result def main(self, text, dict): # 获取正向和逆向分词结果 r1 = self.MMseg(text, dict) r2 = self.RMMseg(text, dict) # 规则1:选择词数较少的结果 if len(r1) != len(r2): return r1 if len(r1) < len(r2) else r2 # 规则2:词数相同时选择单字较少的结果 count_r1 = sum(1 for word in r1 if len(word) == 1) count_r2 = sum(1 for word in r2 if len(word) == 1) if count_r1 != count_r2: return r1 if count_r1 < count_r2 else r2 # 规则3:仍相同则返回逆向结果 return r2 ``` ### 实现逻辑分步说明: 1. **参数修正**:`main` 方应接收 `text` 和 `dict` 参数,而非 `r1` 和 `r2` 2. **获取双向结果**: - 调用 `MMseg` 进行正向最大匹配 → `r1` - 调用 `RMMseg` 进行逆向最大匹配 → `r2` 3. **规则匹配**: - **优先比较词数**:选择分词数量更少的结果 - **单字数量比较**:若词数相同,选择单字(长度=1)较少的结果 - **默认选择**:若仍相同,返回逆向匹配结果(中文中逆向匹配通常更准确) ### 算特点: - **双向对比**:通过正/逆向两种策略降低单方向匹配的误差 - **规则驱动**:通过多级决策规则解决歧义问题 - **时间复杂度**:$O(n)$,与输入文本长度线性相关
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

花来❀勿Q

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

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

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

打赏作者

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

抵扣说明:

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

余额充值