R語言︱情感分析—詞典型代碼實踐(最基礎)(一)
R語言︱情感分析—基於監督算法R語言實現筆記。
可以與博客 R語言︱詞典型情感分析文本操作技巧匯總(打標簽、詞典與數據匹配等)對著看。
詞典型情感分析大致有以下幾個步驟:
訓練數據集、neg/pos情感詞典、分詞+數據清洗清洗(一、二、三級清洗步驟)、計算情感得分、模型評價
————————————————————————————————————————————
《數據挖掘之道》書中幾點贈言:
(1)在分析過程中,難免會產生很多中間變量,它們會占用大量內存。書中提到通常會將所有的臨時中間變量命名為temp,只需要保證下一個temp出現之前,臨時變量不會再延用就可以了。
(2)毫無疑問,如果不追求高大上的算法的話,詞典法不失為一種好方法,其實有時候我們使用了很多方法,結果發現並沒有什麽質變,也浪費了大量時間;
比如在優化詞典的時候,我希望使用高大上的算法解決問題,自動分辨出情感詞,結果浪費了大量的時間,嘗試了卡方統計量、各種分類器等等,結果可想而知,最後還是使用人工的方法將詞典優化了一遍,是的,是用肉眼。
其實有時候看起來最笨的方法也許是現階段最有效最合適最省事的方法,只是它看起來很low,這也許就是笨方法的高深之處,“聰明人”是不屑於使用這些方法的。
(3)僅僅使用詞匯並不能非常準確的識別一條文本所表達的情感傾向。一些修辭手法例如反諷、欲揚先抑等等也會給基於詞典的情感分析造成困難。
————————————————————————————————————————————————
一、訓練數據集
文本作為非結構化數據,在構造訓練集的時候,很少會發給你完整的數據集,可能需要批量讀取txt字符,讀取方式見:R語言︱詞典型情感分析文本操作技巧匯總(打標簽、詞典與數據匹配等),第一節。
`read.csv`函數讀取文件時,可能報警:“EOF
within quoted string”,一般為數據中不正常的符號所致,常見的方法是將`quote =
""`設置為空,這樣做雖然避免了警告,但是仍然解決不了問題,有時數據會對不上號,所以最好從符號上著手將一些特殊符號去除,還有一些文本的正則表達式的問題,可見博客: R語言︱文本(字符串)處理與正則表達式。
本文中導入的數據集是清華大學李軍標註的近24000個酒店評論文本和譚松波整理的12000個來自京東、攜程、當當網的跨行業評論文本。並給出了每個文本數據的評分。李軍老師的數據是眾多的txt文件的評論文本+用rlabelclass文件來存放文本標簽,可以用read.table來調用。
其他的一些市面上的免費語料庫可見博客:情感分析︱網絡公開的免費文本語料訓練數據集匯總
[plain] view plain copy
- train<- read.csv("./train.csv",quote = "",sep = "\"", header = T, stringsAsFactors = F)
- #沒有quote,會出現Warning message:EOF within quoted string
- #讀入csv格式的時候,出現所有字符變成雙引號,需要sep = "\"",來劃分開,字符串分隔符的問題?
會出現的問題:
(1)EOF within quoted string
解決方法:quote="";
(2)CSV格式被讀入R內存中時,所有字符、變量內容都被加了雙引號?
解決方案:需要調整,需要sep = "\"",來劃分開。除了英文逗號可能引起`read.csv`函數讀取csv文件報錯以外,
#還有英文單引號(‘)、英文雙引號(")、波浪號(~),都會引起讀取時發生警告,帶來csv文件或txt文件讀取不完整的後果
————————————————————————————————————————————————————————————————————
二、正向、逆向情感詞典
1、詞典導入與處理
市面上關於情感詞典,有多家研究機構進行了分析,並且公布了結果,比如大連理工、漢語情感詞極值表、臺灣大學情感NTUSD、知網Hownet情感詞、中文褒貶義詞典v1.0(清華大學李軍)等,有些詞典分為正向、逆向單詞兩個部分;有些放在一起,然後有單獨的標簽,可以cbind合並在一起。本文引用的是譚松波老師的正向、逆向情感詞典。
[plain] view plain copy
- #1、情感正向詞,詞組+打“+1”-label
- pos <- read.csv("./pos.csv", header = T, sep = ",", stringsAsFactors = F)
- weight <- rep(1, length(pos[,1]))
- pos <- cbind(pos, weight)
- #2、情感負向詞,詞組+打“-1”-label
- neg <- read.csv("./neg.csv", header = T, sep = ",", stringsAsFactors = F)
- weight <- rep(-1, length(neg[,1]))
- neg <- cbind(neg, weight)
代碼解讀:weight是標簽,主動貼在正向、逆向詞典上。然後進行正向、逆向詞典的合並。
- #3、正、負向詞組合並
- posneg <- rbind(pos, neg) #正負詞典合並
- names(posneg) <- c("term", "weight")
- posneg <- posneg[!duplicated(posneg$term), ]#`duplicated`函數的作用和`unique`函數比較相似,它返回重復項的位置編號
各個詞典對情感詞的傾向定義可能矛盾,出現同一個詞具有情感正向和負向兩種傾向的情況,盡管這種情況更加符合現實,但是違背了基於詞典的情感分析的原假設,所以要將這些詞去重,我們的方法是一個詞如果同時屬於正向和負向,僅保留正向分類。用duplicated語句,保留重復的第一個詞語,詳細可見博客: R語言︱數據去重。
圖1
2、詞典讀入詞庫
另外既然整合了大量的詞典,就要盡量保證分詞器能夠把這些情感詞匯分出來,所以需要將情感詞典添加到分詞器的詞典中去,雖然這種方法在特殊情況下並不一定湊效。
已知了詞典,需要把情感詞放到詞庫裏面,以備後續的匹配、分詞。在這分詞選用Rwordseg包來進行分詞。關於這個包如何下載,是個非常頭疼的問題,參考博客:R語言·文本挖掘︱Rwordseg/rJava兩包的安裝(安到吐血)
[plain] view plain copy
- dict <- posneg[, "term"]
- #library(Rwordseg)
- #listDict() #查看已有詞庫
- #uninstallDict() #刪除安裝的詞典
- insertWords(dict)
關於Rwordseg包,如果已經存放了詞庫,應該先刪除原有的詞庫。
listDict函數是查看詞庫,uninstallDict函數是刪除詞庫,insertWords是把單詞加入詞庫。加入的詞庫,應該是單詞,所以需要posneg[,"term"]項。
————————————————————————————————————————————————————————————————————
三、數據清洗+分詞
1、一、二級清洗
文本挖掘中,對文本的清洗工作尤為重要,會出現比如:英文逗號、波浪線、英文單引號、英文雙引號、分隔符等。一級清洗去掉一些特殊符號,二級清洗去掉一些內容較少、空缺值。詳情見:R語言︱詞典型情感分析文本操作技巧匯總(打標簽、詞典與數據匹配等),第二節。
[plain] view plain copy
- sentence <- as.vector(train.test$msg) #文本內容轉化為向量sentence
- sentence <- gsub("[[:digit:]]*", "", sentence) #清除數字[a-zA-Z]
- sentence <- gsub("[a-zA-Z]", "", sentence) #清除英文字符
- sentence <- gsub("\\.", "", sentence) #清除全英文的dot符號
- train.test <- train.test[!is.na(sentence), ] #清除一些空值文本(文本名)
- sentence <- sentence[!is.na(sentence)] #清除對應sentence裏面的空值(文本內容),要先執行文本名
- train.test <- train.test[!nchar(sentence) < 2, ] #篩選字符數小於2的文本
- sentence <- sentence[!nchar(sentence) < 2] #`nchar`函數對字符計數,英文嘆號為R語言裏的“非”函數
2、分詞
每次可能耗費時間較長的過程,都要使用少量數據預估一下時間,這是一個優秀的習慣
[plain] view plain copy
- system.time(x <- segmentCN(strwords = sentence))
分詞之後需要分出來的詞語,把ID、label加上,如圖2所示。參考 R語言︱詞典型情感分析文本操作技巧匯總(打標簽、詞典與數據匹配等)第四節
[plain] view plain copy
- temp <- lapply(x, length) #每一個元素的長度,即文本分出多少個詞
- temp <- unlist(temp) #lapply返回的是一個list,所以3行unlist
- id <- rep(train.test[, "id"], temp) #將每一個對應的id復制相應的次數,就可以和詞匯對應了
- label <- rep(train.test[, "label"], temp) #id對應的情感傾向標簽復制相同的次數
- term <- unlist(x) #6行將list解散為向量
- testterm <- as.data.frame(cbind(id, term, label), stringsAsFactors = F) #生成一個單詞-文檔-數據框
3、三級清洗——去停用詞
雖然算法已經足夠簡單,沒有必要去除停用詞,但是為了顯示誠意,文本分析裏每一個環節都不能少,這裏還是認真的去除停用詞,真的不是走過場哦。
[plain] view plain copy
- stopword <- read.csv("./stopword.csv", header = T, sep = ",", stringsAsFactors = F)
- stopword <- stopword[!stopword$term %in% posneg$term,]#函數`%in%`在posneg$term中查找stopword的元素,如果查到了就返回真值,沒查到就返回假
- testterm <- testterm[!testterm$term %in% stopword,]#去除停用詞
最後生成了圖2中的前三列,weght是下面關聯情感權重的結果。
圖2
————————————————————————————————————————————————————————————————————
四、情感得分
1、關聯情感權重
已經獲得了訓練集的分詞,而且也有了情感詞典+情感詞權重,那麽如何把情感詞典中的情感權重,加入到訓練集的數據集中呢?
這時候需要進行詞庫之間的匹配,可見博客R語言︱詞典型情感分析文本操作技巧匯總(打標簽、詞典與數據匹配等)第五節。
用plyr包中的join函數就可以匹配、並合並。
[plain] view plain copy
- library(plyr)
- testterm <- join(testterm, posneg)
- testterm <- testterm[!is.na(testterm$weight), ]
- head(testterm)
2、計算情感得分
關聯了情感權重,那麽每個文檔的得分自然而然可以求得,以weight為例,進行分組匯總即可,用aggregate函數。
[plain] view plain copy
- #2、計算情感指數
- dictresult <- aggregate(weight ~ id, data = testterm, sum)
- dictlabel <- rep(-1, length(dictresult[, 1]))
- dictlabel[dictresult$weight > 0] <- 1 #很有技巧地把情感詞語正負賦值到情感得分表中
- dictresult <- as.data.frame(cbind(dictresult, dictlabel), stringsAsFactors = F)
圖3
得到了如圖3中weight的數列,為了與原來的文本分類進行比較,需要簡單知道每個文本的情感偏向,得分>0則偏向為1,得分<0,偏向為-1,這時候引入了一個輔助列,dictlabel來進行這樣的操作。
dictlabel[dictresult$weight > 0] <- 1是輔助列運算的精華語句。
3、模型評價
[plain] view plain copy- ###模型評價
- temp <- unique(testterm[, c("id", "label")])
- dictresult <- join(dictresult, temp)
- evalue <- table(dictresult$dictlabel, dictresult$label)
最後可以和原先的分類進行混淆矩陣評價。從結果查看,並不是很精確。
從執行的過程中我們也發現,很多不具有情感色彩的詞被定義為了情感詞,例如的、了、還、在、我、都、把、上等字詞,這些字詞都是高頻字詞,而我們的計算方法按照出現頻次重復計算,所以導致上面的結果偏差很大。
暫時的改進辦法:修改優化詞典,去除這類詞匯,或者更改為去重計算,即一條評論中某詞無論出現多少次都只計算一次權重。
R語言︱情感分析—詞典型代碼實踐(最基礎)(一)