文本預處理學習(2)

R包之tm:文本挖掘包


原文地址: http://www.bagualu.net/wordpress/archives/6112 

本文參考文檔:

  1. tm的使用指南 : http://mirror.bjtu.edu.cn/cran/web/packages/tm/vignettes/tm.pdf
  2. tm手冊 : http://mirror.bjtu.edu.cn/cran/web/packages/tm/tm.pdf

簡介

tm 即text mining,是用來做文本挖掘的一個R包,是一個進行自然語言處理的基礎包。它提供了一些做文本挖掘的基礎設施,比如數據輸入,文集處理,預處理,元數據管理,創建單詞-文本矩陣。

安裝

該包的安裝方法是install.packages("tm")

數據輸入—文集(corpus)

文集代表一個文檔集,通常一個文件就是一個文檔。多個文檔構成一個文集。文集是一個抽象的概念,具體的實現方式有幾種,一個是VCorpus(Volatile Corpus),這種文集完全存儲在內存中。故而不能很大。這個文集的創建方法爲 VCorpus(x,readerControl)。 另一個實現是PCorpus1 (Permanent Corpus),這種實現方式下,內存中只是存儲文檔的指針,真正的文檔存儲在磁盤上(文件或者數據庫)。

文集創建的第一個參數x必須是一個Source對象,tm提供了一些預定義的source。比如DirSrouce,VectorSource,DataframeSource等,它們分別用來處理一個目錄,一個向量(每個元素爲一個文檔),和數據框結構(比如csv)的文檔。可以利用getSources()來得到所有可用的source,用戶也可以建立自己的source。

文集創建的第二個參數是readerControl,這個參數必需是一個列表,其中包含組件readerlanguage。其中:

  • reader負責創建一個文檔。而文檔的來源是source傳遞過來的每個元素。下面是簡單的處理流程

    source  --> elements ---> reader ---> document

    其中,tm包中有幾種reader,比如readPlain(),readPDF(),readDOC()等等,可以利用getReaders()來獲得所有可以的reader

    每個source都對應有一個缺省的reader,比如DirSource的reader就是讀入文件,把文件的內容作爲字符串。這個reader是可以被替換的。

  • language 指明文本的語言

因此,對於包tm目錄下的texts/txt目錄下的文本文件可以這樣做成一個文集

library(tm)
#> Loading required package: NLP
txt <- system.file("texts","txt",package="tm")
vid = VCorpus(DirSource(txt, encoding = "UTF-8"), readerControl = list(language="lat"))
vid
#> <<VCorpus>>
#> Metadata:  corpus specific: 0, document level (indexed): 0
#> Content:  documents: 5

最簡單的VectorSource,可以用來最簡單的測試,比如

docs <- c("hello doc1", "hello doc2") 
VCorpus(VectorSource(docs))
#> <<VCorpus>>
#> Metadata:  corpus specific: 0, document level (indexed): 0
#> Content:  documents: 2

最後可以看一個指定外部reader的例子

reut21578 <- system.file("texts", "crude", package = "tm")
reuters <- VCorpus(DirSource(reut21578),
                    readerControl = list(reader = readReut21578XMLasPlain))

數據輸出

文集中的數據可以直接輸出,比如前面讀入的文集,可以這樣寫到磁盤上去writeCorpus(vid), 每個文檔會生成一個文件

查看語料庫(corpora)

print(vid)只是給出了最簡單的信息,要查看更多的信息,可使用inspect()

查看某幾條信息

inspect(vid[1:2])
#> <<VCorpus>>
#> Metadata:  corpus specific: 0, document level (indexed): 0
#> Content:  documents: 2
#> 
#> [[1]]
#> <<PlainTextDocument>>
#> Metadata:  7
#> Content:  chars: 676
#> 
#> [[2]]
#> <<PlainTextDocument>>
#> Metadata:  7
#> Content:  chars: 700

查看單個文檔元數據

meta(vid[[2]])
#>   author       : character(0)
#>   datetimestamp: 2016-03-09 01:45:14
#>   description  : character(0)
#>   heading      : character(0)
#>   id           : ovid_2.txt
#>   language     : lat
#>   origin       : character(0)

查看單個文檔內容

as.character(vid[[2]])
#>  [1] "    quas Hector sensurus erat, poscente magistro"   
#>  [2] "         verberibus iussas praebuit ille manus."    
#>  [3] "    Aeacidae Chiron, ego sum praeceptor Amoris:"    
#>  [4] "         saevus uterque puer, natus uterque dea."   
#>  [5] "    sed tamen et tauri cervix oneratur aratro,"     
#>  [6] ""                                                   
#>  [7] "         frenaque magnanimi dente teruntur equi;"   
#>  [8] "    et mihi cedet Amor, quamvis mea vulneret arcu"  
#>  [9] "         pectora, iactatas excutiatque faces."      
#> [10] "    quo me fixit Amor, quo me violentius ussit,"    
#> [11] "         hoc melior facti vulneris ultor ero:"      
#> [12] ""                                                   
#> [13] "    non ego, Phoebe, datas a te mihi mentiar artes,"
#> [14] "         nec nos aëriae voce monemur avis,"         
#> [15] "    nec mihi sunt visae Clio Cliusque sorores"      
#> [16] "         servanti pecudes vallibus, Ascra, tuis:"   
#> [17] "    usus opus movet hoc: vati parete perito;"

查看多個文檔內容

lapply(vid[1:2],as.character)
#> $ovid_1.txt
#>  [1] "    Si quis in hoc artem populo non novit amandi,"    
#>  [2] "         hoc legat et lecto carmine doctus amet."     
#>  [3] "    arte citae veloque rates remoque moventur,"       
#>  [4] "         arte leves currus: arte regendus amor."      
#>  [5] ""                                                     
#>  [6] "    curribus Automedon lentisque erat aptus habenis," 
#>  [7] "         Tiphys in Haemonia puppe magister erat:"     
#>  [8] "    me Venus artificem tenero praefecit Amori;"       
#>  [9] "         Tiphys et Automedon dicar Amoris ego."       
#> [10] "    ille quidem ferus est et qui mihi saepe repugnet:"
#> [11] ""                                                     
#> [12] "         sed puer est, aetas mollis et apta regi."    
#> [13] "    Phillyrides puerum cithara perfecit Achillem,"    
#> [14] "         atque animos placida contudit arte feros."   
#> [15] "    qui totiens socios, totiens exterruit hostes,"    
#> [16] "         creditur annosum pertimuisse senem."         
#> 
#> $ovid_2.txt
#>  [1] "    quas Hector sensurus erat, poscente magistro"   
#>  [2] "         verberibus iussas praebuit ille manus."    
#>  [3] "    Aeacidae Chiron, ego sum praeceptor Amoris:"    
#>  [4] "         saevus uterque puer, natus uterque dea."   
#>  [5] "    sed tamen et tauri cervix oneratur aratro,"     
#>  [6] ""                                                   
#>  [7] "         frenaque magnanimi dente teruntur equi;"   
#>  [8] "    et mihi cedet Amor, quamvis mea vulneret arcu"  
#>  [9] "         pectora, iactatas excutiatque faces."      
#> [10] "    quo me fixit Amor, quo me violentius ussit,"    
#> [11] "         hoc melior facti vulneris ultor ero:"      
#> [12] ""                                                   
#> [13] "    non ego, Phoebe, datas a te mihi mentiar artes,"
#> [14] "         nec nos aëriae voce monemur avis,"         
#> [15] "    nec mihi sunt visae Clio Cliusque sorores"      
#> [16] "         servanti pecudes vallibus, Ascra, tuis:"   
#> [17] "    usus opus movet hoc: vati parete perito;"

變換(transformation)

變換指通過tm_map函數來對文集中所有的文檔作用一個函數的過程。比如停用詞剔除等。每個變換隻是作用在一個文檔 上,tm_map來把它作用到所有的文檔。

比如

  • 剔除多餘的空白tm_map(vid,stripWhitespace)
  • 轉換爲小寫 tm_map(vid,content_transformer(tolower))

    其中的content_transformer是一個修改文檔內容的方便的函數,tolower可以是任何其他的字符串修改函數

  • 移除停用詞

    reuters <- tm_map(reuters, removeWords, stopwords("english"))

過濾器

過濾器可以移除不感興趣的(或者感興趣的)文檔。tm提供了tm_filter函數,這個函數的原型爲

  1. tm_filter(x, FUN,...)
  2. tm_index(x,FUN,...)

其中的FUN函數出入爲一片文檔,輸出爲一個bool值。表示是否接受該文檔。第二個版本tm_index 只是返回滿足條件的index,前者返回一個文集,下面是一個使用示例:

data("crude")
# Full-text search
tm_filter(crude, FUN = function(x) any(grep("co[m]?pany", content(x))))

元數據管理

元數據分爲兩個層次,一個是文集級別的元數據,一個是文檔級別的元數據。要獲得元數據,最簡單的是 使用meta()函數。每篇文檔,有些預定義的元數據(比如author),但是每篇文檔也可以添加自定義的 元數據標籤。如下所示,分別用DublinCoremeta函數來修改一個文檔的元數據

data(crude)
DublinCore(crude[[1]], "Creator") <- "Ano Nymous"
meta(crude[[1]])
#>   author       : Ano Nymous
#>   datetimestamp: 1987-02-26 17:00:56
#>   description  : 
#>   heading      : DIAMOND SHAMROCK (DIA) CUTS CRUDE PRICES
#>   id           : 127
#>   language     : en
#>   origin       : Reuters-21578 XML
#>   topics       : YES
#>   lewissplit   : TRAIN
#>   cgisplit     : TRAINING-SET
#>   oldid        : 5670
#>   places       : usa
#>   people       : character(0)
#>   orgs         : character(0)
#>   exchanges    : character(0)
meta(crude[[1]], "author") <- "Jiang Hang"
meta(crude[[1]])
#>   author       : Jiang Hang
#>   datetimestamp: 1987-02-26 17:00:56
#>   description  : 
#>   heading      : DIAMOND SHAMROCK (DIA) CUTS CRUDE PRICES
#>   id           : 127
#>   language     : en
#>   origin       : Reuters-21578 XML
#>   topics       : YES
#>   lewissplit   : TRAIN
#>   cgisplit     : TRAINING-SET
#>   oldid        : 5670
#>   places       : usa
#>   people       : character(0)
#>   orgs         : character(0)
#>   exchanges    : character(0)

下面是修改文集級別元數據的列子

meta(crude, tag = "url", type = "corpus") <- "http://www.bagualu.net"
meta(crude, type = "corpus")
#> $url
#> [1] "http://www.bagualu.net"
#> 
#> attr(,"class")
#> [1] "CorpusMeta"

每個元數據的數據可以是dataframe結構的。

標準操作和函數

標準的操作符[,[[,[<-,[[<-,c(),lapply()可以直接作用在corpora(語料庫)上

創建文檔-單詞矩陣

tm中,函數TermDocumentMatrixDocumentTermMatrix可直接創建文檔-單詞矩陣,這二者的卻別 在於矩陣的行是文檔還是單詞

dtm <- DocumentTermMatrix(reuters)
inspect(dtm[5:10, 740:743])
#> <<DocumentTermMatrix (documents: 6, terms: 4)>>
#> Non-/sparse entries: 2/22
#> Sparsity           : 92%
#> Maximal term length: 9
#> Weighting          : term frequency (tf)
#> 
#>      Terms
#> Docs  needs. negative negotiate neither
#>   211      0        0         0       0
#>   236      0        0         0       0
#>   237      1        0         0       0
#>   242      0        0         0       0
#>   246      0        0         0       0
#>   248      0        1         0       0

文檔-單詞矩陣的操作

有了矩陣以後,可以有很多R函數可以作用於它,但是tm包提供了一些常用的函數,比如你想找到那些至少 出現了10次的單詞,使用findFreqTerms()函數

findFreqTerms(dtm,10)
#>  [1] "about"      "and"        "are"        "bpd"        "but"       
#>  [6] "crude"      "dlrs"       "for"        "from"       "government"
#> [11] "has"        "its"        "kuwait"     "last"       "market"    
#> [16] "mln"        "new"        "not"        "official"   "oil"       
#> [21] "one"        "opec"       "pct"        "price"      "prices"    
#> [26] "reuter"     "said"       "said."      "saudi"      "sheikh"    
#> [31] "that"       "the"        "they"       "u.s."       "was"       
#> [36] "were"       "will"       "with"       "would"

又比如,要找到與單詞opec有0.8以上相關性的單詞,使用findAssocs()

findAssocs(dtm,"opec",0.8)
#> $opec
#>   meeting emergency       oil      15.8  analysts    buyers     above 
#>      0.88      0.87      0.87      0.85      0.85      0.83      0.82 
#>      said   ability 
#>      0.82      0.80

文檔-單詞矩陣通常很大。tm提供了移除稀疏元素的函數

inspect(removeSparseTerms(dtm,0.4))
#> <<DocumentTermMatrix (documents: 20, terms: 8)>>
#> Non-/sparse entries: 140/20
#> Sparsity           : 12%
#> Maximal term length: 6
#> Weighting          : term frequency (tf)
#> 
#>      Terms
#> Docs  and for its oil reuter said the was
#>   127   1   2   3   5      1    1   5   1
#>   144   9   5   6  11      1    9  17   1
#>   191   0   2   1   2      1    1   4   0
#>   194   1   2   1   1      1    1   4   1
#>   211   2   2   1   1      1    3   8   0
#>   236   7   4   8   7      1    6  15   7
#>   237  11   3   3   3      1    0  30   2
#>   242   3   1   0   3      1    3   6   1
#>   246   9   6   3   4      1    4  18   2
#>   248   6   2   2   9      1    5  27   4
#>   273   5   4   0   5      1    5  21   1
#>   349   2   0   0   3      1    1   5   0
#>   352   3   0   2   5      1    1   7   1
#>   353   1   2   2   4      1    1   4   3
#>   368   1   0   1   3      1    2  11   2
#>   489   5   4   2   4      1    2   8   0
#>   502   6   5   2   4      1    2  13   0
#>   543   0   3   2   2      1    2   5   1
#>   704   5   3   1   3      1    3  21   0
#>   708   0   0   0   1      1    0   0   1

字典

字典是字符串的集合,通常用一個字符串向量表示,可以在DocumentTermMatrix函數中指定一個 字典,這樣生成的矩陣中,就只有字典中出現的詞語,不在字典中的詞語不會出現在文檔單詞矩陣中 如下所示

inspect(DocumentTermMatrix(reuters,
                          list(dictionary = c("prices", "crude", "oil"))))
#> <<DocumentTermMatrix (documents: 20, terms: 3)>>
#> Non-/sparse entries: 41/19
#> Sparsity           : 32%
#> Maximal term length: 6
#> Weighting          : term frequency (tf)
#> 
#>      Terms
#> Docs  crude oil prices
#>   127     2   5      3
#>   144     0  11      3
#>   191     2   2      0
#>   194     3   1      0
#>   211     0   1      0
#>   236     1   7      2
#>   237     0   3      0
#>   242     0   3      1
#>   246     0   4      0
#>   248     0   9      7
#>   273     5   5      4
#>   349     2   3      0
#>   352     0   5      4
#>   353     2   4      1
#>   368     0   3      0
#>   489     0   4      2
#>   502     0   4      2
#>   543     2   2      2
#>   704     0   3      2
#>   708     1   1      0

關於中文支持

利用缺省的reader讀入文檔時,如果文檔爲中文,tm還是會以空格作爲單詞的分割符。這樣基本對中文不適用。爲了能夠處理中文,需要 圖換掉缺省的reader。新的reader應該讀入文章,並進行分詞,然後將分詞的結果保存爲一個新的文件,該文件中,各中文單詞以空格隔開 。然後再利用tm的缺省reader進行處理就可以了。關於自定義reader的格式,詳見這篇博客


rmmseg4j 以前在cran中的,後來被移除了,原因是不符合java的源碼政策 ( Archived on 2014-08-30 as does not comply with policy on Java sources. )


  1. 對於PCorpus而言,第三個參數dbControl必須是一個列表,它具有組件dbNamedbType (這個dbType必須是filehash包支持的數據庫類型)。這裏不做詳細討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章