首页 / 资讯中心 / 文章详情

从词典匹配到二元语法:手把手入门中文分词与NLP基础

从词典匹配到二元语法:手把手入门中文分词与NLP基础 ★ FEATURED ARTICLE
简介这份资源是南京邮电大学自然语言处理课程实验一的完整实验报告面向正在学习中文分词与句法分析的高校学生及自学者帮助其理解词典分词与二元语法分词的基本原理并完成实验任务。报告围绕HanLP工具展开涵盖segment分词指令与--no-tag参数用法、文件输入输出处理、parse句法分析及依存关系解读并给出前向最长匹配、后向最长匹配与双向最长匹配三种算法的分词结果对比和差异说明还附有基于pyhanlp的Python实现代码。资源包共1个doc文件约232KB以实验报告文档形式呈现结构贴合课程实验流程便于对照填写与复盘。已有428人学习下载适合需要参考实验步骤、核对分词结果或补充代码实现的学习者使用。1. 分词这件事其实比你想的更接地气你有没有想过手机输入法为什么能猜出你下一句想打什么搜索引擎为什么能在一大段话里找到你要的那个词这背后有一个最基础、也最容易被忽略的步骤——把一整句话切成一个个有意义的词。中文里这叫“分词”英文里叫 word segmentation。听起来像学术黑话但你每天都在用它。自然语言处理NLP入门的第一课几乎都是从分词开始的。原因很简单中文不像英文有空格隔开单词“结婚的和尚未结婚的”这句话机器看到的就是一串连续的汉字它得先决定怎么切才能继续往下理解。这份实验资源就是带你从零手搓这件事用词典匹配的方法切词再用二元语法bigram统计的方法切词最后跑通一个能实际输出结果的例子。适合谁刚接触 NLP、装了 Python 但不知道从哪下手、看到“语料库”“词性标注”就发怵的新手。读完你至少能自己跑出第一行分词结果。2. 先搞懂两个概念词典分词和二元语法到底在干嘛2.1 词典分词拿一本“词表”去句子里对号入座想象你手里有一本厚厚的词典里面列着所有你认为算“词”的字符串。现在给你一句话你从第一个字开始看最多能匹配到词典里多长的词匹配上了就切出来然后从下一个字继续。这就是最朴素的词典分词也叫最长匹配法。它分三种常见玩法前向最长匹配从左往右扫每次尽量取最长的词。后向最长匹配从右往左扫同样尽量取最长。双向最长匹配两种都跑一遍按规则挑一个更靠谱的结果。拿“结婚的和尚未结婚的”举例前向匹配可能切出[结婚, 的, 和尚, 未, 结婚, 的]把“和尚未”切成了“和尚 未”后向匹配则切出[结婚, 的, 和, 尚未, 结婚, 的]明显更符合语义。双向匹配会综合两者降低这种翻车概率。你看词典分词不难难的是歧义——同一串字不同切法意思完全不一样。2.2 二元语法分词不查词典靠“谁跟谁常一起出现”来切词典分词依赖一本现成的词表词表里没有的新词就抓瞎。二元语法分词换了个思路我不告诉你哪些是词我给你一堆已经分好词的句子叫语料你统计一下相邻两个字/词一起出现的频率。切分的时候哪种切法让相邻词对的出现概率最高就选哪种。比如语料里有“商品 和 服务”“商品 和服 物美价廉”“服务 和 货币”统计完你会发现“商品”后面跟“和”的次数是 2“和”后面跟“服务”的次数也是 2。那给“商品和服务”分词时商品 / 和 / 服务这条路径的联合概率就比商品 / 和服 / 务更靠谱。这就是统计语言模型的入门版不靠规则靠数据说话。2.3 为什么新手要先学这两个而不是直接上深度学习我第一次学 NLP 的时候也想过现在都有大模型了还学词典匹配干嘛后来踩了坑才明白词典分词和二元语法是理解所有后续模型的“地基”。你后面遇到的隐马尔可夫、条件随机场、甚至 BERT 的分词器底层逻辑都绕不开“怎么切、为什么这样切”。而且这两个方法代码量极小跑通只要几十行能让你在第一天就获得“我确实让机器处理了中文”的正反馈。先建立手感再谈原理这是最不容易放弃的路径。3. 动手跑第一个例子从装环境到出结果3.1 环境准备Python 加一个中文处理库这份实验用的是 HanLP 这个中文处理工具包Python 3.7 或 3.8 都能跑。你不需要理解它内部怎么实现先把它当成一个“分词黑匣子”用起来。打开命令行装好依赖pip install pyhanlp装完之后第一次运行会自动下载词典数据稍微等一会儿。如果你在 Windows 上遇到编码报错别慌后面避坑章节会讲。验证是否装好跑一行from pyhanlp import HanLP # 最简单的分词调用输出带词性的结果 print(HanLP.segment(商品和服务))这段代码的意思很直白把“商品和服务”交给 HanLP 的默认分词器打印结果。你会看到类似[商品/n, 和/cc, 服务/vn]的输出斜杠后面是词性标注n 是名词cc 是连词vn 是动名词。如果你只想要词、不想要词性后面加参数或者用--no-tag的思路处理即可。3.2 用命令行快速试几句建立直觉HanLP 装好后自带命令行入口适合你快速试不同句子、观察切分差异hanlp segment进入交互模式后依次输入这几句看看输出商品和服务 当下雨天地面积水分外严重 结婚的和尚未结婚的确实在干扰分词啊第一句你会看到商品/n, 和/cc, 服务/vn第二句是当/p, 下雨天/n, 地面/n, 积水/n, 分外/d, 严重/a第三句里“和尚”和“尚未”的歧义会被正确处理成结婚/vi, 的/ude1, 和/cc, 尚未/d, 结婚/vi...。这一步的目的不是背结果而是让你亲眼看到同一套工具对不同歧义句的处理策略是不一样的。你输入得越多对“分词难在哪”的体感就越强。3.3 第一个完整脚本文件进、文件出命令行玩熟了写一个能批量处理文件的脚本才算真正迈进门。假设你有一个input1.txt里面是一段中文你想分词后写到output1.txtfrom pyhanlp import HanLP # 读入原始文本 with open(input1.txt, encodingutf-8) as f: text f.read() # 分词ShowTermNature 设为 False 表示不显示词性 HanLP.Config.ShowTermNature False words HanLP.segment(text) # 把结果拼成空格分隔的字符串写入输出文件 result .join(str(w) for w in words) with open(output1.txt, w, encodingutf-8) as f: f.write(result) print(分词完成共切出, len(words), 个词)逐行解释一下encodingutf-8是防止中文乱码的关键很多新手第一次翻车就翻在这里ShowTermNature False控制输出里要不要带/n这种词性标记 .join(...)把词列表拼成一行方便你肉眼检查。跑完打开output1.txt你应该能看到类似春分 最 具 灵性 的 美 是 千 色 万 彩 ...的结果。到这一步你已经完成了“读文件 → 分词 → 写文件”的完整闭环后面所有实验都是在这个骨架上加东西。4. 再进一步自己训练一个二元语法模型4.1 准备一份迷你语料亲手喂给模型词典分词你已经在用了现在试试二元语法。新建一个文件my_cws_corpus.txt内容就四行词与词之间用空格隔开商品 和 服务 商品 和服 物美价廉 服务 和 货币这四行就是你的“训练数据”。别嫌少入门阶段数据越少你越容易看清每一步在干什么。接下来用 HanLP 的语料加载和词典构建工具把这份语料训练成一个模型from pyhanlp import SafeJClass # 加载语料转成句子列表 CorpusLoader SafeJClass(com.hankcs.hanlp.corpus.document.CorpusLoader) NatureDictionaryMaker SafeJClass(com.hankcs.hanlp.corpus.dictionary.NatureDictionaryMaker) def train_bigram(corpus_path, model_path): sents CorpusLoader.convert2SentenceList(corpus_path) # 给每个词统一打上词性标签 n入门阶段不用纠结词性 for sent in sents: for word in sent: word.setLabel(n) maker NatureDictionaryMaker() maker.compute(sents) maker.saveTxtTo(model_path) train_bigram(my_cws_corpus.txt, my_cws_corpus_model)跑完之后你会得到三个文件my_cws_corpus_model.txt是一元模型每个词出现了几次my_cws_corpus_model.ngram.txt是二元模型相邻词对出现了几次还有一个.tr.txt跟词性标注有关入门阶段可以先不管。这三个文件就是你的“小型语言知识库”。4.2 加载模型查词频、跑分词模型训练好了怎么用先查两个词的频率验证模型确实学到了东西from pyhanlp import HanLP, SafeJClass def load_bigram(model_path): # 告诉 HanLP 用我们自己训练的模型而不是默认大词典 HanLP.Config.CoreDictionaryPath model_path .txt HanLP.Config.BiGramDictionaryPath model_path .ngram.txt CoreDictionary SafeJClass(com.hankcs.hanlp.dictionary.CoreDictionary) print(商品:, CoreDictionary.getTermFrequency(商品)) print(和:, CoreDictionary.getTermFrequency(和)) load_bigram(my_cws_corpus_model)输出应该是商品: 2和和: 2因为你的语料里“商品”出现两次、“和”也出现两次。这说明模型文件被正确加载了。接着用这个模型对“商品和服务”做分词from pyhanlp import HanLP, JClass HanLP.Config.CoreDictionaryPath my_cws_corpus_model.txt HanLP.Config.BiGramDictionaryPath my_cws_corpus_model.ngram.txt ViterbiSegment JClass(com.hankcs.hanlp.seg.Viterbi.ViterbiSegment) segment ViterbiSegment() print(segment.seg(商品和服务))结果会是[商品/n, 和/n, 服务/n]。注意这里的“和”被标成了 n因为训练时我们统一打了 n 标签这不影响分词本身。你可能会问这跟默认分词有什么区别区别在于默认分词用的是 HanLP 自带的大词典而这里用的是你四行语料训出来的小模型。数据少效果自然糙但流程是完整的——你亲手走了一遍“语料 → 统计 → 模型 → 分词”的链路这比背十遍概念都管用。5. 新手最容易踩的五个坑5.1 一跑就报 UnicodeDecodeError现象打开文件时抛出UnicodeDecodeError: gbk codec cant decode byte...。原因Windows 默认用 GBK 编码读文件而你的文本是 UTF-8 存的编码对不上。解决所有open()都显式写上encodingutf-8包括读和写。这是血泪经验我第一次跑实验卡了半小时就因为这个。5.2 分词结果里全是/null现象用DoubleArrayTrieSegment输出类似[春分/null, 之/null, ...]。原因这个分词器只做词典匹配不负责词性标注所以词性位置是 null。解决这是正常现象不是代码错了。如果你只关心切分结果忽略/null即可想要词性就换回HanLP.segment()。5.3 自己训练的模型分词效果“很傻”现象用四行语料训出来的模型切“春分之特别”结果惨不忍睹。原因语料太小模型没见过那些词统计概率全是零。解决入门阶段接受这个结果它的目的是让你理解流程不是追求效果。想提升就加语料但那是下一步的事。5.4 命令行hanlp segment找不到命令现象终端提示hanlp 不是内部或外部命令。原因pyhanlp装在了某个 Python 环境里但该环境的 Scripts 目录没加进系统 PATH。解决直接用 Python 脚本调用HanLP.segment()绕开命令行入口或者确认你激活的是装包的那个环境。5.5 停用词去除后标点全变星号现象去掉停用词后逗号句号也被替换成了*。原因停用词表里包含了标点符号替换逻辑一视同仁。解决这是预期行为不是 bug。如果你只想去虚词、保留标点需要自己过滤停用词表把标点剔出去。入门阶段先接受原样输出理解机制比调结果重要。6. 下一步学什么把这条链路走宽跑通分词和二元语法之后你其实已经站在 NLP 的门口了。接下来怎么走我给你一条我当初希望有人告诉我的路径。第一周把分词吃透。别急着换模型先把前向、后向、双向最长匹配用纯 Python 各写一遍不用 HanLP就用手写循环加一个set当词典。写完你会对“歧义”有肌肉记忆。然后拿同一句话分别跑三种匹配对比结果差异记录哪种情况谁翻车。第二周理解词性标注和句法分析在干嘛。实验里出现的hanlp parse输出那一堆“主谓关系”“动宾关系”不用深究算法但你要能看懂一棵依存树大概在描述什么。找一个简单句手动画出词与词的关系再对照工具输出看看差在哪。第三周换一个分词器对比。HanLP 自带多种分词模式试试StandardTokenizer和NLPTokenizer对同一段新闻的切分差异。重点不是谁更准而是观察“为什么同一句话不同工具切得不一样”这会逼你去想模型假设的差别。第四周碰一碰序列标注。二元语法本质是统计相邻词对而现代分词主流是序列标注给每个字打 B/M/E/S 标签。你可以先不写代码找一篇讲 BMES 标注的入门文章读一遍再回头看你的二元语法模型会发现思路是一脉相承的都是从数据里学“怎么切”。一个具体技巧每次跑新代码前先用三五个短句做“冒烟测试”确认输出格式对了再上长文本。我早期图省事直接拿整篇文章跑结果一个编码错误埋在几百行输出里排查了半天。从那以后我每次换模型、换文件都强制先用一句“商品和服务”走一遍全流程确认管道通了再放量。这个习惯帮我省下的时间比任何调参技巧都多。希望帮到你先从第一行HanLP.segment(商品和服务)跑起来剩下的路会越走越顺。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站