1. 中文斷詞基礎流程
1.1 載入資料
Python Result
Copy with open("data/blessing.txt", encoding="utf8") as fin:
text = fin.read()
print(type(fin))
print(type(text))
print("Number of characters: %d" % len(text))
print(text[:int(len(text)/10)])
1.2 斷句
在斷句前先清除每個段落前的首行縮排(兩個全形空白)。並且取代換行符號(要注意並不是每次都先取代換行符號,比方說你可以比較一下這章節所用的文本和PTT文章在斷句上的差異)。
Python Result
Copy text_refined = text.replace(" ", "").replace("\n", "")
sentences = text_refined.split("。")
print("Number of sentences: %d" % len(sentences))
print(sentences[:20])
Copy ['舊曆的年底畢竟最像年底,村鎮上不必說,就在天空中也顯出將到新年的氣象來', '灰白色的沉重的晚雲中間時時發出閃光,接著一聲鈍響,是送竈的爆竹;近處燃放的可就更強烈了,震耳的大音還沒有息,空氣裏已經散滿了幽微的火藥香', '我是正在這一夜回到我的故鄉魯鎮的', '雖說故鄉,然而已沒有家,所以只得暫寓在魯四老爺的宅子裏', '他是我的本家,比我長一輩,應該稱之曰「四叔」,是一個講理學的老監生', '他比先前並沒有甚麽大改變,單是老了些,但也還未留鬍子,一見面是寒暄,寒暄之後說我「胖了」,說我「胖了」之後即大罵其新黨', '但我知道,這並非借題在罵我:因為他所罵的還是康有為', '但是,談話是總不投機的了,於是不多久,我便一個人剩在書房裏', '第二天我起得很遲,午飯之後,出去看了幾個本家和朋友;第三天也照樣', '他們也都沒有甚麽大改變,單是老了些;家中卻一律忙,都在準備著「祝福」', '這是魯鎮年終的大典,致敬盡禮,迎接福神,拜求來年一年中的好運氣的', '殺雞,宰鵝,買豬肉,用心細細的洗,女人的臂膊都在水裏浸得通紅,有的還帶著絞絲銀鐲子', '煮熟之後,橫七豎八的插些筷子在這類東西上,可就稱為「福禮」了,五更天陳列起來,並且點上香燭,恭請福神們來享用,拜的卻只限於男人,拜完自然仍然是放爆竹', '年年如此,家家如此,——只要買得起福禮和爆竹之類的——今年自然也如此', '天色愈陰暗了,下午竟下起雪來,雪花大的有梅花那麽大,滿天飛舞,夾著煙靄和忙碌的氣色,將魯鎮亂成一團糟', '我回到四叔的書房裏時,瓦楞上已經雪白,房裏也映得較光明,極分明的顯出壁上掛著的朱拓的大「壽」字,陳摶老祖寫的,一邊的對聯已經脫落,鬆鬆的卷了放在長桌上,一邊的還在,道是「事理通達心氣和平」', '我又無聊賴的到窗下的案頭去一翻,只見一堆似乎未必完全的《康熙字典》,一部《近思錄集註》和一部《四書襯》', '無論如何、我明天決計要走了', '況且,一直到昨天遇見祥林嫂的事,也就使我不能安住', '那是下午,我到鎮的東頭訪過一個朋友,走出來,就在河邊遇見她;而且見她瞪著的眼睛的視線,就知道明明是向我走來的']
Number of sentences: 273
1.3 斷詞
Python Result 測試 2
Copy # !pip install jieba
import jieba
print(sentences[0])
print(jieba.cut(sentences[0]))
print(list(jieba.cut(sentences[0])))
舊曆的年底畢竟最像年底,村鎮上不必說,就在天空中也顯出將到新年的氣象來
<generator object Tokenizer.cut at 0X114658d50>
['舊曆', '的', '年底', '畢竟', '最', '像', '年底', ',', '村鎮', '上', '不必', '說', ',', '就', '在', '天空', '中', '也', '顯出', '將到', '新年', '的', '氣象', '來']
Copy import jieba
print(" / ".join(jieba.cut(sentences[0])))
print(" / ".join(jieba.cut("台北市長柯文哲")))
舊曆 / 的 / 年底 / 畢竟 / 最 / 像 / 年底 / , / 村鎮 / 上 / 不必 / 說 / , / 就 / 在 / 天空 / 中 / 也 / 顯出 / 將到 / 新年 / 的 / 氣象 / 來
台北市 / 長 / 柯文 / 哲
2. 繁簡斷詞效果比較
jieba套件在繁簡兩種字體的斷詞效果差不少,必須要謹慎考量。但若要用結巴,比較好的方法應該是先轉為簡體,然後用簡體斷詞的位置來斷開繁體句子。
2.1 繁簡互換
繁轉簡,問題不大,但簡又轉回繁,幾乎跟原本的繁體字意義都不同了。
Python Testing 2 Result
Copy # !pip install hanziconv
from hanziconv import HanziConv
sim = HanziConv.toSimplified('臺北市長柯文哲')
print(sim)
tra = HanziConv.toTraditional(sim)
print(tra)
台北市长柯文哲
颱北市長柯文哲
Copy sim = HanziConv.toSimplified('第二天我起得很遲,午飯之後,出去看了幾個本家和朋友')
print(sim)
tra = HanziConv.toTraditional(sim)
print(tra)
Copy 第二天我起得很迟,午饭之后,出去看了几个本家和朋友
第二天我起得很遲,午飯之後,齣去看瞭幾個本傢和朋友
2.2 繁簡斷詞結果比較
Copy tra = '台北市長柯文哲'
sim = HanziConv.toSimplified(tra)
print(" / ".join(jieba.cut(tra)))
print(" / ".join(jieba.cut(sim)))
台北市 / 長 / 柯文 / 哲 # 直接斷繁體
台北 / 市长 / 柯文 / 哲 # 直接斷簡體
簡體斷詞再轉繁 測試二
Copy sim = HanziConv.toSimplified(sentences[0])
sim_cutted = list(jieba.cut(sim))
sim_cutted_to_tra = [HanziConv.toTraditional(term) for term in sim_cutted]
print(" / ".join(sim_cutted_to_tra))
print(" / ".join(jieba.cut(sim)))
舊曆 / 的 / 年底 / 畢竟 / 最像 / 年底 / , / 村鎮 / 上 / 不必 / 說 / , / 就 / 在 / 天空 / 中 / 也 / 顯齣 / 將 / 到 / 新年 / 的 / 氣象 / 來
旧历 / 的 / 年底 / 毕竟 / 最像 / 年底 / , / 村镇 / 上 / 不必 / 说 / , / 就 / 在 / 天空 / 中 / 也 / 显出 / 将 / 到 / 新年 / 的 / 气象 / 来
Copy tra = "國民黨高雄市長候選人韓國瑜今天晚上開直播,針對最近引起爭議的一些事說明,強調他並沒有消費愛心菜販陳樹菊,全力支持「館長」做公益,所謂高雄三鳳宮靈籤可能是「新型態選舉詐騙」;至於為強調招商引資說出「陪睡」遭批,他以後不會說這麼有張力的用語,畢竟是市長候選人。"
sim = HanziConv.toSimplified(tra)
sim_cutted = list(jieba.cut(sim))
sim_cutted_tra = [HanziConv.toTraditional(term) for term in sim_cutted]
print(" / ".join(jieba.cut(tra)))
print(" / ".join(sim_cutted_tra))
print(" / ".join(jieba.cut(sim)))
國民黨 / 高雄市 / 長 / 候選人 / 韓國瑜 / 今天 / 晚上 / 開 / 直播 / , / 針對 / 最近 / 引起 / 爭議 / 的 / 一些 / 事 / 說明 / , / 強調 / 他 / 並沒有 / 消費 / 愛心 / 菜販 / 陳樹菊 / , / 全力支持 / 「 / 館長 / 」 / 做 / 公益 / , / 所謂 / 高雄 / 三鳳 / 宮靈 / 籤 / 可能 / 是 / 「 / 新型 / 態選舉 / 詐騙 / 」 / ; / 至於 / 為 / 強調 / 招商 / 引資 / 說 / 出 / 「 / 陪 / 睡 / 」 / 遭批 / , / 他 / 以後不會 / 說 / 這麼 / 有 / 張力 / 的 / 用語 / , / 畢 / 竟是 / 市長 / 候選人 / 。
國民黨 / 高雄市 / 長 / 候選人 / 韓國 / 瑜 / 今天 / 晚上 / 開 / 直播 / , / 針對 / 最近 / 引起爭議 / 的 / 一些 / 事 / 說明 / , / 強調 / 他 / 並 / 沒有 / 消費 / 愛心 / 菜販 / 陳樹菊 / , / 全力支持 / 「 / 館長 / 」 / 做 / 公益 / , / 所謂 / 高雄 / 三鳳宮 / 靈簽 / 可能 / 是 / 「 / 新型 / 態 / 選舉 / 詐騙 / 」 / ; / 至於 / 為 / 強調 / 招商引資 / 說齣 / 「 / 陪 / 睡 / 」 / 遭批 / , / 他 / 以後 / 不會 / 說 / 這麼 / 有 / 張力 / 的 / 用語 / , / 畢竟 / 是 / 市長 / 候選人 / 。
国民党 / 高雄市 / 长 / 候选人 / 韩国 / 瑜 / 今天 / 晚上 / 开 / 直播 / , / 针对 / 最近 / 引起争议 / 的 / 一些 / 事 / 说明 / , / 强调 / 他 / 并 / 没有 / 消费 / 爱心 / 菜贩 / 陈树菊 / , / 全力支持 / 「 / 馆长 / 」 / 做 / 公益 / , / 所谓 / 高雄 / 三凤宫 / 灵签 / 可能 / 是 / 「 / 新型 / 态 / 选举 / 诈骗 / 」 / ; / 至于 / 为 / 强调 / 招商引资 / 说出 / 「 / 陪 / 睡 / 」 / 遭批 / , / 他 / 以后 / 不会 / 说 / 这么 / 有 / 张力 / 的 / 用语 / , / 毕竟 / 是 / 市长 / 候选人 / 。
2.3 用簡體斷詞位置切割繁體字詞
方法一(推薦)
Copy def restore(text, toks):
results = []
offset = 0
for tok in toks:
results.append(text[offset:offset + len(tok)])
offset += len(tok)
return results
print(restore(tra, list(jieba.cut(HanziConv.toSimplified(tra)))))
['國民黨', '高雄市', '長', '候選人', '韓國', '瑜', '今天', '晚上', '開', '直播', ',', '針對', '最近', '引起爭議', '的', '一些', '事', '說明', ',', '強調', '他', '並', '沒有', '消費', '愛心', '菜販', '陳樹菊', ',', '全力支持', '「', '館長', '」', '做', '公益', ',', '所謂', '高雄', '三鳳宮', '靈籤', '可能', '是', '「', '新型', '態', '選舉', '詐騙', '」', ';', '至於', '為', '強調', '招商引資', '說出', '「', '陪', '睡', '」', '遭批', ',', '他', '以後', '不會', '說', '這麼', '有', '張力', '的', '用語', ',', '畢竟', '是', '市長', '候選人', '。']
方法一(測試二)
Copy # Segmenting traditional Chinese directly
sample = "國民黨高雄市長候選人韓國瑜今天晚上開直播,針對最近引起爭議的一些事說明,強調他並沒有消費愛心菜販陳樹菊,全力支持「館長」做公益,所謂高雄三鳳宮靈籤可能是「新型態選舉詐騙」;至於為強調招商引資說出「陪睡」遭批,他以後不會說這麼有張力的用語,畢竟是市長候選人。"
print(" / ".join(jieba.cut(sample)))
# Segmenting traditional Chinese by cutted simplified index
print("/ ".join(restore(sample, list(jieba.cut(HanziConv.toSimplified(sample))))))
國民黨 / 高雄市 / 長 / 候選人 / 韓國瑜 / 今天 / 晚上 / 開 / 直播 / , / 針對 / 最近 / 引起 / 爭議 / 的 / 一些 / 事 / 說明 / , / 強調 / 他 / 並沒有 / 消費 / 愛心 / 菜販 / 陳樹菊 / , / 全力支持 / 「 / 館長 / 」 / 做 / 公益 / , / 所謂 / 高雄 / 三鳳 / 宮靈 / 籤 / 可能 / 是 / 「 / 新型 / 態選舉 / 詐騙 / 」 / ; / 至於 / 為 / 強調 / 招商 / 引資 / 說 / 出 / 「 / 陪 / 睡 / 」 / 遭批 / , / 他 / 以後不會 / 說 / 這麼 / 有 / 張力 / 的 / 用語 / , / 畢 / 竟是 / 市長 / 候選人 / 。
國民黨/ 高雄市/ 長/ 候選人/ 韓國/ 瑜/ 今天/ 晚上/ 開/ 直播/ ,/ 針對/ 最近/ 引起爭議/ 的/ 一些/ 事/ 說明/ ,/ 強調/ 他/ 並/ 沒有/ 消費/ 愛心/ 菜販/ 陳樹菊/ ,/ 全力支持/ 「/ 館長/ 」/ 做/ 公益/ ,/ 所謂/ 高雄/ 三鳳宮/ 靈籤/ 可能/ 是/ 「/ 新型/ 態/ 選舉/ 詐騙/ 」/ ;/ 至於/ 為/ 強調/ 招商引資/ 說出/ 「/ 陪/ 睡/ 」/ 遭批/ ,/ 他/ 以後/ 不會/ 說/ 這麼/ 有/ 張力/ 的/ 用語/ ,/ 畢竟/ 是/ 市長/ 候選人/ 。
方法二
Copy import numpy
print(sentences[0])
def tra_cutted_by_sim(tra):
sim_cutted = jieba.cut(HanziConv.toSimplified(tra))
term_len = [len(w) for w in list(sim_cutted)]
term_index = [0] + list(numpy.cumsum(term_len)[:-1])
term_dict = {k:v for k, v, in zip(term_index, term_len)}
tra_cutted = [tra[k:k+v] for k, v in term_dict.items()]
return tra_cutted
print(tra_cutted_by_sim(sentences[0]))
sim_cutted = jieba.cut(HanziConv.toSimplified(sentences[0]))
sim_cutted_to_tra = [HanziConv.toTraditional(term) for term in sim_cutted]
print(sim_cutted_to_tra)
舊曆的年底畢竟最像年底,村鎮上不必說,就在天空中也顯出將到新年的氣象來
['舊曆', '的', '年底', '畢竟', '最像', '年底', ',', '村鎮', '上', '不必', '說', ',', '就', '在', '天空', '中', '也', '顯出', '將', '到', '新年', '的', '氣象', '來']
['舊曆', '的', '年底', '畢竟', '最像', '年底', ',', '村鎮', '上', '不必', '說', ',', '就', '在', '天空', '中', '也', '顯齣', '將', '到', '新年', '的', '氣象', '來']
(Option) 斷詞效果的測試工具
Python Result
Copy tra_cutted = list(jieba.cut(sample))
cut_by_sim = tra_cutted_by_sim(sample)
i, j = 0, 0
print("Cutted tra directly:", tra_cutted)
print("Cutted by sim:", cut_by_sim)
print(len(tra_cutted), len(cut_by_sim))
while i < len(tra_cutted) and j < len(cut_by_sim):
if tra_cutted[i] == cut_by_sim[j]:
print("[%d]%s\t[%d]%s" % (i, tra_cutted[i], j, cut_by_sim[j]))
i += 1
j += 1
else:
ei, ej = 1, 1
listi, listj = [], []
listi.append(tra_cutted[i])
listj.append(cut_by_sim[j])
while "".join(listi) != "".join(listj):
if(len("".join(listi)) < len("".join(listj))):
listi.append(tra_cutted[i+ei])
ei += 1
else:
listj.append(cut_by_sim[j+ej])
ej += 1
print("\t[%d_%d]%s\t[%d_%d]%s" % (i, ei, listi, j, ej, listj))
i += ei
j += ej
Copy 74 74
[0]國民黨 [0]國民黨
[1]高雄市 [1]高雄市
[2]長 [2]長
[3]候選人 [3]候選人
[4_1]['韓國瑜'] [4_2]['韓國', '瑜']
[5]今天 [6]今天
[6]晚上 [7]晚上
[7]開 [8]開
[8]直播 [9]直播
[9], [10],
[10]針對 [11]針對
[11]最近 [12]最近
[12_2]['引起', '爭議'] [13_1]['引起爭議']
[14]的 [14]的
[15]一些 [15]一些
[16]事 [16]事
[17]說明 [17]說明
[18], [18],
[19]強調 [19]強調
[20]他 [20]他
[21_1]['並沒有'] [21_2]['並', '沒有']
[22]消費 [23]消費
[23]愛心 [24]愛心
[24]菜販 [25]菜販
[25]陳樹菊 [26]陳樹菊
[26], [27],
[27]全力支持 [28]全力支持
[28]「 [29]「
[29]館長 [30]館長
[30]」 [31]」
[31]做 [32]做
[32]公益 [33]公益
[33], [34],
[34]所謂 [35]所謂
[35]高雄 [36]高雄
[36_3]['三鳳', '宮靈', '籤'] [37_2]['三鳳宮', '靈籤']
[39]可能 [39]可能
[40]是 [40]是
[41]「 [41]「
[42]新型 [42]新型
[43_1]['態選舉'] [43_2]['態', '選舉']
[44]詐騙 [45]詐騙
[45]」 [46]」
[46]; [47];
[47]至於 [48]至於
[48]為 [49]為
[49]強調 [50]強調
[50_2]['招商', '引資'] [51_1]['招商引資']
[52_2]['說', '出'] [52_1]['說出']
[54]「 [53]「
[55]陪 [54]陪
[56]睡 [55]睡
[57]」 [56]」
[58]遭批 [57]遭批
[59], [58],
[60]他 [59]他
[61_1]['以後不會'] [60_2]['以後', '不會']
[62]說 [62]說
[63]這麼 [63]這麼
[64]有 [64]有
[65]張力 [65]張力
[66]的 [66]的
[67]用語 [67]用語
[68], [68],
[69_2]['畢', '竟是'] [69_2]['畢竟', '是']
[71]市長 [71]市長
[72]候選人 [72]候選人
[73]。 [73]。
3. POS、停用詞、標點符號去除
jieba使用者自定義詞典
Python 測試二
Copy jieba.load_userdict("data/userdict.txt")
print(" / ".join(jieba.cut(sentences[0])))
舊曆 / 的 / 年底 / 畢竟 / 最 / 像 / 年底 / , / 村鎮 / 上 / 不必 / 說 / , / 就 / 在 / 天空 / 中 / 也 / 顯出 / 將到 / 新年 / 的 / 氣象 / 來
Copy print(" / ".join(jieba.cut(sample)))
國民黨 / 高雄市 / 長 / 候選人 / 韓國瑜 / 今天 / 晚上 / 開 / 直播 / , / 針對 / 最近 / 引起 / 爭議 / 的 / 一些 / 事 / 說明 / , / 強調 / 他 / 並沒有 / 消費 / 愛心 / 菜販 / 陳樹菊 / , / 全力支持 / 「 / 館長 / 」 / 做 / 公益 / , / 所謂 / 高雄 / 三鳳宮 / 靈籤 / 可能 / 是 / 「 / 新型 / 態選舉 / 詐騙 / 」 / ; / 至於 / 為 / 強調 / 招商 / 引資 / 說 / 出 / 「 / 陪 / 睡 / 」 / 遭批 / , / 他 / 以後不會 / 說 / 這麼 / 有 / 張力 / 的 / 用語 / , / 畢 / 竟是 / 市長 / 候選人 / 。
標記POS
Python Results
Copy import jieba.posseg
print(list((jieba.posseg.cut(sample))))
[pair('國民黨', 'nt'), pair('高雄市', 'ns'), pair('長候', 'n'), pair('選人', 'n'), pair('韓國瑜', 'x'), pair('今天', 't'), pair('晚上', 't'), pair('開', 'zg'), pair('直播', 'vn'), pair(',', 'x'), pair('針對', 'p'), pair('最近', 'f'), pair('引起', 'v'), pair('爭議', 'n'), pair('的', 'uj'), pair('一些', 'm'), pair('事', 'n'), pair('說', 'v'), pair('明', 't'), pair(',', 'x'), pair('強調', 'v'), pair('他', 'r'), pair('並', 'c'), pair('沒有', 'v'), pair('消費', 'vn'), pair('愛心', 'n'), pair('菜販', 'n'), pair('陳樹菊', 'x'), pair(',', 'x'), pair('全力支持', 'n'), pair('「', 'x'), pair('館長', 'n'), pair('」', 'x'), pair('做', 'v'), pair('公益', 'n'), pair(',', 'x'), pair('所謂', 'b'), pair('高雄', 'n'), pair('三鳳宮', 'x'), pair('靈籤', 'x'), pair('可能', 'v'), pair('是', 'v'), pair('「', 'x'), pair('新型', 'b'), pair('態', 'n'), pair('選舉', 'v'), pair('詐騙', 'vn'), pair('」', 'x'), pair(';', 'x'), pair('至於', 'i'), pair('為', 'p'), pair('強調', 'v'), pair('招商', 'n'), pair('引資說', 'l'), pair('出', 'v'), pair('「', 'x'), pair('陪', 'v'), pair('睡', 'v'), pair('」', 'x'), pair('遭批', 'v'), pair(',', 'x'), pair('他', 'r'), pair('以', 'p'), pair('後', 'nr'), pair('不', 'd'), pair('會', 'v'), pair('說', 'v'), pair('這麼', 'r'), pair('有', 'v'), pair('張力', 'nr'), pair('的', 'uj'), pair('用語', 'n'), pair(',', 'x'), pair('畢', 'zg'), pair('竟是', 'd'), pair('市長候', 'n'), pair('選人', 'n'), pair('。', 'x')]
Copy for word, pos in jieba.posseg.cut(sample):
print("%s\t%s" % (word, pos))
國民黨 nt
高雄市 ns
長候 n
選人 n
韓國瑜 x
今天 t
晚上 t
開 zg
...
去除標點符號並計算詞頻
Copy # Just an testing
import unicodedata
chars = "『「,。、標點符號"
print([unicodedata.category(ch) for ch in chars])
['Ps', 'Ps', 'Po', 'Po', 'Po', 'Lo', 'Lo', 'Lo', 'Lo']
Copy import unicodedata
from collections import Counter
word_counts = Counter()
for sentence in sentences:
for word in jieba.cut(sentence):
if len(word) > 1 or not unicodedata.category(word).startswith('P'):
word_counts[word] += 1
print(word_counts.most_common(20))
[('的', 345), ('了', 197), ('她', 155), ('我', 88), ('是', 86), ('也', 77), ('說', 65), ('在', 61), ('來', 57), ('就', 56), ('裏', 54), ('有', 46), ('麽', 45), ('不', 37), ('祥林嫂', 35), ('又', 34), ('一個', 33), ('你', 33)
, ('去', 32), ('他', 28)]
刪去停用詞
Manipulate a Chinese stopword list.
What is "U+FEFF"? The Unicode character U+FEFF is the byte order mark, or BOM, and is used to tell the difference between big- and little-endian UTF-16 encoding. If you decode the web page using the right codec, Python will remove it for you. Examples:
Sol. 1. Add stop words temporarily
Copy stopwords = ["的", "了", "是", "也", "在"]
Sol. 2. Add stop words from files
Copy with open("data/stopwords_zh-tw.txt", encoding="utf-8") as fin:
stopwords = fin.read().split("\n")[1:]
print(stopwords)
print(len(stopwords))
Remove stop words
Copy import unicodedata
from collections import Counter
word_counts = Counter()
for sentence in sentences:
for word in jieba.cut(sentence):
if word in stopwords:
continue
if len(word) > 1 or not unicodedata.category(word).startswith('P'):
word_counts[word] += 1
print(word_counts.most_common(20))
print(len(word_counts))
Using CKIPTagger
CKIPTagger在沒有GPU資源時非常的慢,所以即使有CPU,跑起來也不快。
他是用bi-lstm,所以要先安裝tensorflow,版本大於1.14,小於2,那就是1.15