這次想學一下中文分詞包jiebaR。額,內容應該有點多,簡單些,不做鋪墊了。

  • jiebaR包介紹:結巴分詞,一款高效的R語言中文分詞包,jieba本身是一個C++庫,jiebaR則是把這個C++庫用R封裝了,所以通過Rcpp進行調用很高效。結巴分詞基於MIT協議,是免費和開源的。另一款常用的中文分詞包是Rwordseg。
  • 包的安裝:jiebaR包是在CRAN發布的標準庫,安裝方式按常規,2條命令就可以了。

install.packages("jiebaR")library("jiebaR")

  • 例子引入:先用個簡單例子查看下jiebaR的妙處。

work <- worker() #用到worker()函數,賦值給workwork["杭州的四月真美麗,想到西湖邊吹吹風。"] #方括弧中是要進行分詞的語句運行結果:> work["杭州的四月真美麗,想到西湖邊吹吹風。"] [1] "杭州" "的" "四月" "真" "美麗" "想到" "西湖" "邊" [9] "吹" "吹風"

語句瞬間瓦解為一個個單詞了,很乾凈利落!

jiebaR提供了3種分詞語句寫法,上面的例子用[ ]符號的語法,還可以使用<=符號語法,或者使用segment()函數。雖然形式不同,但是分詞效果是一樣的。如下:

work <= "杭州的四月真美麗,想到西湖邊吹吹風。" #方式二segment( "杭州的四月真美麗,想到西湖邊吹吹風" , work ) #方式三

如果語句比較長,可以換種寫法:

juzi <- "杭州的四月真美麗,想到西湖邊吹吹風。 靈峯和孤山的梅花,龍井八景的桃花,太子灣的鬱金香, 白堤間株的桃柳,八卦田的油菜花,美不勝收。" #用juzi替代長句子work <- worker()work[juzi] #方式一work <= juzi #方式二segment(juzi,work) #方式三

運行結果:

劃線處的詞沒被正確切分,下文會解釋

  • worker()和segment()語法:jiebaR通過函數worker()來初始化分詞引擎,使用函數segment()進行分詞。兩個函數語法:

——worker()函數

worker()參數釋義

在調用worker()函數時,實際是在載入jiebaR庫的分詞引擎。jiebaR庫提供了7種分詞引擎。

1.混合模型(MixSegment):是四個分詞引擎裡面分詞效果較好的類,結它合使用最大概率法和隱式馬爾科夫模型。2.最大概率法(MPSegment) :負責根據Trie樹構建有向無環圖和進行動態規劃演算法,是分詞演算法的核心。3.隱式馬爾科夫模型(HMMSegment):是根據基於人民日報等語料庫構建的HMM模型來進行分詞,主要演算法思路是根據(B,E,M,S)四個狀態來代表每個字的隱藏狀態。 HMM模型由dict/hmm_model.utf8提供。分詞演算法即viterbi演算法。4.索引模型(QuerySegment):先使用混合模型進行切詞,再對於切出來的較長的詞,枚舉句子中所有可能成詞的情況,找出詞庫裏存在。5.標記模型(tag)6.Simhash模型(simhash)7.關鍵詞模型(keywods)

我是搞不懂引擎的事,直接默認官方推薦的混合模型就好了。

——segment()函數

比worker簡單多啦

有了點基礎,下面嘗試進階點的功能。上例的運行結果中,「吹吹風」、「太子灣」和「八卦田」三個詞是被分開切的,下面通過自定義,讓詞庫更智能的切出正確的詞。

  • 添加用戶自定義詞或詞庫:試驗3種方法。

Way1:使用new_user_word函數

work_new_word<-worker()new_user_word(work_new_word, c("吹吹風","太子灣","八卦田"))segment(juzi,work_new_word)

運行結果:

這樣就OK了

這種方法蠻方便的,但是一旦遇到長文本,詞庫多了,就不太適用了。升級點的方法:

Way2:使用user參數添加詞庫

自定義一個詞庫,然後從詞庫裡面直接讀。我建的詞庫截圖如下:

利用Notepad++編寫一個名為ciku.txt的文檔,放了三個詞:吹吹風、太子灣、八卦田。把這個txt存入getwd()的路徑裏。再利用worker(user)調用:

work_user<-worker(user="ciku.txt")segment(juzi,work_user)

可能會問,為什麼不直接用txt文本呢?我一開始也是直接用txt寫的,發現有毒,一引用R就崩了。有人給出了解答:如果你的詞庫是用記事本寫的話,因為編碼有時不是UTF-8,使用時會出現各種錯誤,甚至軟體奔潰。所以建議使用notepad++編輯,將編碼設置為utf-8,另存為txt文件。)

Way3:借用搜狗細胞詞庫

搜狗提供了大量的專業領域辭彙,其詞庫具有專門的.scel格式,詞庫導出與導入非常麻煩,這時,需要用到搜狗細胞詞庫轉化包cidian,它不僅能夠在R中將搜狗詞庫的scel格式轉化為可讀的詞庫,並且還能直接被分詞包jiebaR調用!但需要注意的是:cidian包沒有發布在CRAN,而是發布在github中,所以需要先獲得開發者工具Rtools才能進行安裝,也要用到install_github()函數。

第一次安裝cidian包的時候,果然又有遇到問題,哎,還好又被我各種探索給解決了,直接上乾貨吧!

#安裝cidian包,時間會有點點長~install.packages("devtools") #R的開發者工具install.packages("stringi") #強大的字元處理包install.packages("pbapply") #能夠為*apply族函數增加進度條install.packages("Rcpp")install.packages("RcppProgress")#Rcpp和RcppProgress讓R直接調用外部的C++程序,增加運算速度library(devtools)install_github("qinwf/cidian") #用來從github上安裝R包的函數,「qinwf」應該是cidian的作者library(cidian)

cidian包安裝完後,下一步,需要自己到搜狗詞庫裏下載想要的詞庫,如圖:

好巧,紅色圈剛好有我想要的「杭州市城市信息精選」詞庫

點進去下載後,詞庫名為:杭州市城市信息精選.scel

把這個scel文件複製到getwd()路徑裏,我是放在默認的C盤用戶文檔裏。

> getwd()[1] "C:/Users/Administrator/Documents"

存放好要用的scel文件後,就可以進行轉化了:

> decode_scel(scel = "./杭州市城市信息精選.scel",cpp = TRUE)output file: ./杭州市城市信息精選.scel_2018-04-19_00_57_55.dict

轉好後,查看生成的詞典文件:

> scan(file="./杭州市城市信息精選.scel_2018-04-19_00_57_55.dict", what=character(),nlines=30,sep=
, encoding=utf-8,fileEncoding=utf-8)輸出為:Read 30 items [1] "阿棒 n" "阿寶 n" "阿寶飯店 n" "阿寶童裝 n" [5] "阿波羅 n" "阿波羅酒店 n" "阿初 n" "阿迪達斯 n" [9] "阿東飯店 n" "阿芬 n" "阿國飯店 n" "阿拉丁 n" [13] "阿里山大酒店 n" "阿良飯店 n" "阿龍造型 n" "阿瑪施 n" [17] "阿瑪施服飾 n" "阿曼尼 n" "阿明網吧 n" "阿潘老湯麵 n" [21] "阿三飯店 n" "阿湯麵館 n" "阿偉 n" "阿香婆 n" [25] "阿依蓮 n" "阿英煲 n" "阿英川菜館 n" "愛得利 n" [29] "愛德醫院 n" "愛都 n"

接下來,需要把這個想要的詞典放到R的分詞庫裏。用show_dictpath()函數查看默認詞典位置。

#查看默認詞庫> show_dictpath()[1] "D:/R/R-3.4.4/library/jiebaRD/dict"

也可以調用函數,查看目前系統自帶的詞庫:

> dir(show_dictpath())[1] "D:/R/R-3.4.4/library/jiebaRD/dict" [1] "backup.rda" "hmm_model.utf8" "hmm_model.zip" "idf.utf8" [5] "idf.zip" "jieba.dict.utf8" "jieba.dict.zip" "model.rda" [9] "README.md" "stop_words.utf8" "user.dict.utf8"

詞庫對應的內容為:

jieba.dict.utf8, 系統詞典文件,最大概率法,utf8編碼的hmm_model.utf8, 系統詞典文件,隱式馬爾科夫模型,utf8編碼的user.dict.utf8, 用戶詞典文件,utf8編碼的stop_words.utf8,停止詞文件,utf8編碼的idf.utf8,IDF語料庫,utf8編碼的jieba.dict.zip,jieba.dict.utf8的壓縮包hmm_model.zip,hmm_model.utf8的壓縮包idf.zip,idf.utf8的壓縮包backup.rda,無注釋model.rda,無注釋README.md,說明文件

重點來了,把搜狗詞典文件改名,從杭州市城市信息精選.scel_2018-04-19_00_57_55.dictuser.dict.utf8,然後替換D:/R/R-3.4.4/library/jiebaRD/dict目錄下面的user.dict.utf8。這樣默認的用戶詞典,就是搜狗詞典了,可以檢驗下新的user.dict.utf8:

> scan(file="D:/R/R-3.4.4/library/jiebaRD/dict/user.dict.utf8",+ what=character(),nlines=30,sep=
,encoding=utf-8,+ fileEncoding=utf-8)Read 30 items [1] "阿棒 n" "阿寶 n" "阿寶飯店 n" "阿寶童裝 n" [5] "阿波羅 n" "阿波羅酒店 n" "阿初 n" "阿迪達斯 n" [9] "阿東飯店 n" "阿芬 n" "阿國飯店 n" "阿拉丁 n" [13] "阿里山大酒店 n" "阿良飯店 n" "阿龍造型 n" "阿瑪施 n" [17] "阿瑪施服飾 n" "阿曼尼 n" "阿明網吧 n" "阿潘老湯麵 n" [21] "阿三飯店 n" "阿湯麵館 n" "阿偉 n" "阿香婆 n" [25] "阿依蓮 n" "阿英煲 n" "阿英川菜館 n" "愛得利 n" [29] "愛德醫院 n" "愛都 n"

對了,是杭州市城市信息精選這個詞庫。

  • 停止詞過濾

停止詞是分詞過程中,我們不需要作為結果的詞,比如:我、你、的、是,a,the,or,and等。這些詞在統計詞頻的時候意義不大,且會增加噪音,需要對這些詞進行過濾。

在jiebaR中,過濾停止詞有2種方法,一種是通過配置stop_word文件,另一種是使用filter_segment()函數。

Way 1:配置stop_word文件

先利用Notepad++編寫一個名為stop_word.txt的文檔,裡麪包含「的」、「和」。

把stop_word.txt存入getwd()的路徑裏。再利用worker()函數調用:

#載入分詞引擎,並配置停止詞過濾> work = worker(stop_word="stop_word.txt")> guolv <- segment(juzi,work)> guolv [1] "杭州" "四月" "真" "美麗" "想到" "西湖" [7] "邊" "吹" "吹風" "靈峯" "孤山" "梅花" [13] "龍井八景" "桃花" "太子灣" "鬱金香" "白堤" "間株" [19] "桃柳" "八卦田" "油菜花" "美不勝收"

禁用「的」,「和」後,運行結果裏果然也沒有這兩個字了,搞定~

Way 2: filter_segment()函數

在上面的過濾基礎上,利用filter_segment()繼續過濾掉「想到」、「邊」兩個詞:

> filter<-c("想到","邊")> filter_segment(guolv,filter) [1] "杭州" "四月" "真" "美麗" "西湖" "吹" [7] "吹風" "靈峯" "孤山" "梅花" "龍井八景" "桃花" [13] "太子灣" "鬱金香" "白堤" "間株" "桃柳" "八卦田" [19] "油菜花" "美不勝收"

  • 關鍵詞提取

前面講了這麼多,都是關於如何更好的進行分詞。做好分詞這一步,更核心的就是提取關鍵詞。TF-IDF演算法是提取關鍵詞的經典演算法。

TF(Term Frequenc),詞頻。一個詞在文章中出現的次數越多,重要性也越大(過濾停用詞)。

IDF(Inverse Document Frequency),逆文檔頻率。在詞頻的基礎上,要對每個詞分配一個"重要性"權重。最常見的詞("的"、"是")給予較小的權重,,較少見的詞("太子灣"、"八卦田")給予較大的權重。這個權重叫做"逆文檔頻率",它的大小與一個詞的常見程度成反比。jiebaR包中的idf.utf8文件,為IDF語料庫,用來模擬語言的使用環境,計算好逆文檔頻率。

TF-TDF = 詞頻TF * 逆文檔頻率IDF

某個詞對文章的重要性越高,它的TF-IDF值就越大。所以,排在最前面的幾個詞,就是這篇文章的關鍵詞。

學習完原理後,可以著手實操一下了。先查看在安裝目錄中的IDF的語料庫——idf.utf8文件。

> scan(file="D:/R/R-3.4.4/library/jiebaRD/dict/idf.utf8",+ what=character(),nlines=20,sep=
,+ encoding=utf-8,fileEncoding=utf-8)Read 20 items [1] "勞動防護 13.900677652" "生化學 13.900677652" [3] "奧薩貝爾 13.900677652" "考察隊員 13.900677652" [5] "崗上 11.5027823792" "倒車檔 12.2912397395" [7] "編譯 9.21854642485" "蝶泳 11.1926274509" [9] "外委 11.8212361103" "故作高深 11.9547675029"[11] "尉遂成 13.2075304714" "心源性 11.1926274509" [13] "現役軍人 10.642581114" "杜勃留 13.2075304714" [15] "包天笑 13.900677652" "賈政陪 13.2075304714" [17] "託爾灣 13.900677652" "多瓦 12.5143832909" [19] "多瓣 13.900677652" "巴斯特爾 11.598092559"

idf.utf8文件每一行有2列,第一列是詞項,第二列為權重,即IDF值,如「生化學」是13.9。然後,計算文檔詞頻(TF),用到freq()函數:

> freq(guolv) char freq1 桃柳 12 間株 13 桃花 14 龍井八景 15 油菜花 16 梅花 17 孤山 1

句子編的不夠完美,每個詞的頻數都為1…不過不影響結果。接下來獲取TF-TDF前5的關鍵詞:

> keys <- worker("keywords",topn=5)> vector_keywords(guolv,keys) 11.8212 11.7392 11.7392 11.7392 11.7392 "靈峯" "太子灣" "桃柳" "間株" "八卦田"

哦yeah!五個關鍵詞提取好了!

篇幅有點長了,關於jiebaR更多的用法,會在下一篇結合Rvest包和wordcloud2包綜合應用。


本文參考文檔:

李曉文:5分鐘上手R語言中文分詞包jiebaR

jiebaR,從入門到喜歡

R文本挖掘|如何在用戶詞庫中添加搜狗詞典?_hao123上網導航

TF-IDF與餘弦相似性的應用(一):自動提取關鍵詞

推薦閱讀:

相关文章