{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 如何使用jieba結巴中文分詞" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![tag-cloud](https://ithelp.ithome.com.tw/upload/images/20171219/20107576LXAdzuZue5.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: 本文主要修改與擷取了[林志傑-如何使用 JIEBA 結巴中文分詞程式](http://blog.fukuball.com/ru-he-shi-yong-jieba-jie-ba-zhong-wen-fen-ci-cheng-shi/)的內容。\n", "文字雲的圖像來源為[GoatWang-2018 iT 邦幫忙鐵人賽](https://ithelp.ithome.com.tw/articles/10192043?sc=rss.qu)。\n", "\n", "對中文的斷詞有興趣強烈建議可以參考:[中文斷詞:斷句不要悲劇](https://speakerdeck.com/fukuball/head-first-chinese-text-segmentation)\n", "\n", "本文主要是為了後續介詔word2vec的理論與實作的前置準備。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "自然語言處理(Natural Language Processing)的其中一個重要環節就是中文斷詞的處理,比起英文斷詞,中文斷詞在先天上就比較難處理,比如電腦要怎麼知道「全台大停電」要斷詞成「全台 / 大 / 停電」呢?如果是英文「Power outage all over Taiwan」,就可以直接用空白字元來斷成「Power / outage / all / over / Taiwan」,可見中文斷詞真的是一個大問題啊~!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[结巴 (jieba) 中文分詞](https://github.com/fxsjy/jieba)是很好很簡單使用的Python中文分詞函式庫。\n", "它有以下的特色:\n", "* 支持三種分詞模式:\n", " * 精確模式,試圖將句子最精確地切開,適合文本分析。\n", " * 全模式,把句子中所有的可以成詞的詞語都掃描出來,速度非常快,但是不能解決歧義。\n", " * 搜索引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜索引擎分詞。\n", "* 支持繁體分詞\n", "* 支持自定義詞典\n", "* MIT授權協議\n", "\n", "jieba中文斷詞所使用的演算法是基於 Trie Tree 結構去生成句子中中文字所有可能成詞的情況,然後使用動態規劃(Dynamic programming)算法來找出最大機率的路徑,這個路徑就是基於詞頻的最大斷詞結果。對於辨識新詞(字典詞庫中不存在的詞)則使用了 HMM 模型(Hidden Markov Model)及 Viterbi 算法來辨識出來。\n", "\n", "在[中文斷詞-by Mark Chang](https://www.slideshare.net/ckmarkohchang/chinese-words-segmentation-tutorial)的分享裡有詳細的解說。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 安裝 jieba\n", "\n", "方法#1\n", "`pip install jieba`\n", "\n", "方法#2\n", "`conda install -c conda-forge jieba`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 基本斷詞用法,使用預設詞庫\n", "\n", "三種分詞模式示範:\n", "* 精確模式,試圖將句子最精確地切開,適合文本分析。\n", "* 全模式,把句子中所有的可以成詞的詞語都掃描出來,速度非常快,但是不能解決歧義。\n", "* 搜索引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合用於搜索引擎分詞。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Building prefix dict from the default dictionary ...\n", "Loading model from cache /var/folders/vt/rfsxsh1j2b51dffzl9p5v72ngb1v7q/T/jieba.cache\n", "Loading model cost 0.929 seconds.\n", "Prefix dict has been built succesfully.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "全模式: 我/ 來/ 到/ 新竹/ 清/ 華/ 大/ 學\n", "精確模式: 我來/ 到/ 新竹/ 清華大學\n", "精確模式(預設): 他來/ 到/ 了/ 台北/ 101/ 大樓\n", "搜索引擎模式模式: Apache/ / Spark/ 是/ 一個/ 開源/ 叢集/ 運算/ 框架/ ,/ 最初/ 是/ 由/ 加州/ 大學柏克萊/ 分校/ AMPLab/ 所開發/ 。\n" ] } ], "source": [ "# encoding=utf-8\n", "import jieba\n", "\n", "seg_list = jieba.cut(\"我來到新竹清華大學\", cut_all=True)\n", "print(\"全模式: \" + \"/ \".join(seg_list)) # 全模式\n", "\n", "seg_list = jieba.cut(\"我來到新竹清華大學\", cut_all=False)\n", "print(\"精確模式: \" + \"/ \".join(seg_list)) # 精確模式\n", "\n", "seg_list = jieba.cut(\"他來到了台北101大樓\") # 預設為精確模式\n", "print(\"精確模式(預設): \" +\"/ \".join(seg_list))\n", "\n", "seg_list = jieba.cut_for_search(\"Apache Spark是一個開源叢集運算框架,最初是由加州大學柏克萊分校AMPLab所開發。\") # 搜索引擎模式\n", "print(\"搜索引擎模式模式: \" +\"/ \".join(seg_list))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "據原作者的說法,使用預設詞庫的話,繁體中文的斷詞結果應該會比較差,畢竟原來的詞庫是簡體中文。我們接下來試試看中文歌詞的斷詞結果如何。\n", "\n", "現在我們使用[回聲樂團 - 座右銘](http://www.indievox.com/song/1)的歌詞作為中文斷詞測試範例,歌詞我們先做成一個純文字檔lyric.txt置放到跟這個jupyter notebook相同的目錄下。\n", "\n", "內容如下:\n", "\n", ">我沒有心\n", "我沒有真實的自我\n", "我只有消瘦的臉孔\n", "所謂軟弱\n", "所謂的順從一向是我\n", "的座右銘\n", "\n", ">而我\n", "沒有那海洋的寬闊\n", "我只要熱情的撫摸\n", "所謂空洞\n", "所謂不安全感是我\n", "的墓誌銘\n", "\n", ">而你\n", "是否和我一般怯懦\n", "是否和我一般矯作\n", "和我一般囉唆\n", "\n", ">而你\n", "是否和我一般退縮\n", "是否和我一般肌迫\n", "一般地困惑\n", "\n", ">我沒有力\n", "我沒有滿腔的熱火\n", "我只有滿肚的如果\n", "所謂勇氣\n", "所謂的認同感是我\n", "隨便說說\n", "\n", ">而你\n", "是否和我一般怯懦\n", "是否和我一般矯作\n", "是否對你來說\n", "只是一場遊戲\n", "雖然沒有把握\n", "\n", ">而你\n", "是否和我一般退縮\n", "是否和我一般肌迫\n", "是否對你來說\n", "只是逼不得已\n", "雖然沒有藉口" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "精確模式: 我/ 沒/ 有心/ \n", "/ 我/ 沒/ 有/ 真實/ 的/ 自我/ \n", "/ 我/ 只有/ 消瘦/ 的/ 臉孔/ \n", "/ 所謂/ 軟弱/ \n", "/ 所謂/ 的/ 順/ 從/ 一向/ 是/ 我/ \n", "/ 的/ 座/ 右銘/ \n", "/ \n", "/ 而/ 我/ \n", "/ 沒有/ 那/ 海洋/ 的/ 寬闊/ \n", "/ 我/ 只要/ 熱情/ 的/ 撫/ 摸/ \n", "/ 所謂/ 空洞/ \n", "/ 所謂/ 不安全感/ 是/ 我/ \n", "/ 的/ 墓誌/ 銘/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 怯懦/ \n", "/ 是否/ 和/ 我/ 一般/ 矯作/ \n", "/ 和/ 我/ 一般/ 囉/ 唆/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 退縮/ \n", "/ 是否/ 和/ 我/ 一般/ 肌迫/ \n", "/ 一般/ 地/ 困惑/ \n", "/ \n", "/ 我/ 沒/ 有力/ \n", "/ 我/ 沒/ 有/ 滿腔/ 的/ 熱火/ \n", "/ 我/ 只有/ 滿肚/ 的/ 如果/ \n", "/ 所謂/ 勇氣/ \n", "/ 所謂/ 的/ 認/ 同感/ 是/ 我/ \n", "/ 隨便/ 說/ 說/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 怯懦/ \n", "/ 是否/ 和/ 我/ 一般/ 矯作/ \n", "/ 是否/ 對/ 你/ 來/ 說/ \n", "/ 只是/ 一場/ 遊戲/ \n", "/ 雖然/ 沒/ 有把握/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 退縮/ \n", "/ 是否/ 和/ 我/ 一般/ 肌迫/ \n", "/ 是否/ 對/ 你/ 來/ 說/ \n", "/ 只是/ 逼不得已/ \n", "/ 雖然/ 沒有/ 藉口/ \n", "\n" ] } ], "source": [ "import jieba\n", "\n", "content = open('lyric.txt', 'rb').read()\n", "\n", "seg_list = jieba.cut(content, cut_all=False)\n", "print(\"精確模式: \" + \"/ \".join(seg_list)) # 精確模式" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我們可以從結果看出斷詞已經開始出了一些問題,比如「座右銘」被斷成了「座 / 右銘」,「墓誌銘」被斷成了「墓誌 / 銘」,這應該就是因為預設詞庫是簡體中文所造成,因此繁體中文的斷詞結果會比較差,還好 jieba 也提供了可以切換詞庫的功能,並提供了一個繁體中文詞庫,所以我們可以使用切換詞庫的功能來改善斷詞結果。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 中文歌詞斷詞,使用繁體詞庫\n", "\n", "從 https://github.com/fxsjy/jieba/blob/master/extra_dict/dict.txt.big 下載繁體詞庫檔,置放到跟這個jupyter notebook相同的目錄下。\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Building prefix dict from /Users/8703147/pythonworks/dict.txt.big ...\n", "Loading model from cache /var/folders/vt/rfsxsh1j2b51dffzl9p5v72ngb1v7q/T/jieba.u7693eb24db7dff9a9936cf7ca1f4b9b9.cache\n", "Loading model cost 1.590 seconds.\n", "Prefix dict has been built succesfully.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "精確模式: 我/ 沒有/ 心/ \n", "/ 我/ 沒有/ 真實/ 的/ 自我/ \n", "/ 我/ 只有/ 消瘦/ 的/ 臉孔/ \n", "/ 所謂/ 軟弱/ \n", "/ 所謂/ 的/ 順從/ 一向/ 是/ 我/ \n", "/ 的/ 座右銘/ \n", "/ \n", "/ 而/ 我/ \n", "/ 沒有/ 那/ 海洋/ 的/ 寬闊/ \n", "/ 我/ 只要/ 熱情/ 的/ 撫摸/ \n", "/ 所謂/ 空洞/ \n", "/ 所謂/ 不安全感/ 是/ 我/ \n", "/ 的/ 墓誌銘/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 怯懦/ \n", "/ 是否/ 和/ 我/ 一般/ 矯作/ \n", "/ 和/ 我/ 一般/ 囉唆/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 退縮/ \n", "/ 是否/ 和/ 我/ 一般/ 肌迫/ \n", "/ 一般/ 地/ 困惑/ \n", "/ \n", "/ 我/ 沒有/ 力/ \n", "/ 我/ 沒有/ 滿腔/ 的/ 熱火/ \n", "/ 我/ 只有/ 滿肚/ 的/ 如果/ \n", "/ 所謂/ 勇氣/ \n", "/ 所謂/ 的/ 認同感/ 是/ 我/ \n", "/ 隨便說說/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 怯懦/ \n", "/ 是否/ 和/ 我/ 一般/ 矯作/ \n", "/ 是否/ 對/ 你/ 來說/ \n", "/ 只是/ 一場/ 遊戲/ \n", "/ 雖然/ 沒有/ 把握/ \n", "/ \n", "/ 而/ 你/ \n", "/ 是否/ 和/ 我/ 一般/ 退縮/ \n", "/ 是否/ 和/ 我/ 一般/ 肌迫/ \n", "/ 是否/ 對/ 你/ 來說/ \n", "/ 只是/ 逼不得已/ \n", "/ 雖然/ 沒有/ 藉口/ \n", "\n" ] } ], "source": [ "import jieba\n", "\n", "# 指定使用繁體詞庫\n", "jieba.set_dictionary('dict.txt.big') \n", "\n", "content = open('lyric.txt', 'rb').read()\n", "\n", "seg_list = jieba.cut(content, cut_all=False)\n", "print(\"精確模式: \" + \"/ \".join(seg_list))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我們在程式中多加一行 jieba.set_dictionary('dict.txt.big'),這樣就可以將斷詞詞庫切換到 dic.txt.big 這個檔案。\n", "\n", "得到的斷詞結果會是:\n", ">我 / 沒有 / 心 / 我 / 沒有 / 真實 / 的 / 自我 / 我 / 只有 / 消瘦 / 的 / 臉孔 / 所謂 / 軟弱 / 所謂 / 的 / 順從 / 一向 / 是 / 我 / 的 / 座右銘 / 而 / 我 / 沒有 / 那 / 海洋 / 的 / 寬闊 / 我 / 只要 / 熱情 / 的 / 撫摸 / 所謂 / 空洞 / 所謂 / 不安全感 / 是 / 我 / 的 / 墓誌銘 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 和 / 我 / 一般 / 囉唆 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 一般 / 地 / 困惑 / 我 / 沒有 / 力 / 我 / 沒有 / 滿腔 / 的 / 熱火 / 我 / 只有 / 滿肚 / 的 / 如果 / 所謂 / 勇氣 / 所謂 / 的 / 認同感 / 是 / 我 / 隨便說說 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 是否 / 對 / 你 / 來說 / 只是 / 一場 / 遊戲 / 雖然 / 沒有 / 把握 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 是否 / 對 / 你" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我們可以看到「座右銘」成功斷成「座右銘」了!「墓誌銘」也成功斷成「墓誌銘」了!果然切換成繁體中文詞庫還是有用的!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 參考\n", "* [林志傑-如何使用 JIEBA 結巴中文分詞程式](http://blog.fukuball.com/ru-he-shi-yong-jieba-jie-ba-zhong-wen-fen-ci-cheng-shi/)\n", "* [结巴中文分词Github](https://github.com/fxsjy/jieba)\n", "* [中文斷詞:斷句不要悲劇](https://speakerdeck.com/fukuball/head-first-chinese-text-segmentation)\n", "* [結巴斷詞器與FastTag](http://blog.pulipuli.info/2017/11/fasttag-identify-part-of-speech-in.html)\n", "* [中文自然語言處理基礎](https://ithelp.ithome.com.tw/articles/10192043?sc=rss.qu)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.4" } }, "nbformat": 4, "nbformat_minor": 2 }