文本分析
2018-09-03
2018-09-03
1 文本分析介绍
在现实生活中,文本也是数据形式之一,文本分析是对文本的表示及其特征项的选取,它把从文本中抽取出的特征词进行量化后表示文本信息。文本分析一般是数据解析,数据探索,文本挖掘三部分。解析数据主要是为了将日志,网页,xml,json等非格式化的数据处理成格式化的数据。数据探索主要是指对解析后的数据分析其关键字,主题,以及相关性等。文本挖掘是对探索后的结果再进行建模分析更深层次的关系。
2 分词及词频统计
首先是将需要分词的文本导入到R中,这里使用已脱敏的数据集,数据集是关于某地区酒店的用户评论。采用jiebaR包进行分词。
jieba支持三种分词模式 :
1. 精确模式,试图将句子最精确地切开,适合文本分析;
2. 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
3. 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。这里采用精确模式分词,代码如下:
comments <- read.csv("E:\\comment.csv")# 导入数据集,记得改成你自己的文件路径
comments.f <- comments$Comment
text <- paste(comments.f)# 将所有的记录融合成一个字符串
library(jiebaR)# 加载分词包
cutter=worker()# 设置分词引擎
segWords <- segment(text,cutter)# 对文本进行分词处理
segWords <- gsub("[0-9a-zA-Z]+?","",segWords)# 去除数字和英文
library(stringr)# 加载stringr包
segWords2 <- str_trim(segWords)# 去除空格
library(plyr)# 加载plyr包
tableWord <- count(segWords2)# 统计词频
write.csv(tableWord,"E:\\wordcount.csv",append = TRUE,row.names = FALSE)# 将结果保存为csv文件
3 数据处理
3.1 去除停用词
现在在你的E盘查看词频统计后的结果,发现词频中还是有一些我们不需要的停用词和无意义的词,例如:的、地、得。所以这里还需要去掉停用词。当然,想要进一步做更精确的分析,需要自己设计语料库。所以再进一步进行筛选。
首先需要一个包含大多数停用词的词库,将这些停用词从词频统计结果中删除。
library(tm)
tableWordnew <- as.character(segWords2)
stopwords <- read.table("C:\\Users\\test\\Desktop\\唐甜R\\文本分析\\中文停用词库.txt")
sw <- as.character(stopwords[[1]])# 因为stopwords为数据框,将停用词转化为字符型数据
stopwordsCN <- enc2utf8(sw) #转utf-8
stopwordsCN <- stopwordsCN[Encoding(stopwordsCN)!="unknown"]#去除未知编码字符
wordResult <- removeWords(tableWordnew, stopwordsCN)# 删除停用词
tableWord <- count(wordResult)
write.csv(tableWord,"E:\\wordnew.csv",append = TRUE,row.names = FALSE)# 将结果保存为csv文件
再对结果进行手动删除一些无意义但是停用词没有删掉的词语。tm包有专门文本数据处理的函数。
函数 | 作用 |
---|---|
tm_map(reuters, as.PlainTextDocument) | 转化纯文本 |
tm_map(reuters, stripWhitespace) | 去除空白 |
tm_map(reuters, tolower) | 小写变化 |
tm_map(reuters, removeWords, stopwords(“english”)) | 停止词去除 |
tm_map(ovid,removeNumbers) | 剔除数字 |
3.2 词向量
词向量的每一维的值代表一个具有一定的语义和语法上解释的特征。故可以将词向量的每一维称为一个词语特征。词向量用Distributed Representation表示,一种低维实数向量。
文档向量化是text2vec的主要功能。运用text2vec包主要分三步:构建一个文档-词频矩阵或者词频共现矩阵;在DTM基础上拟合模型,包括文本分类、情感分析、聚类、主题模型、相似性度量等。并进行模型的调试和验证。
text2vec提供了函数测量距离/相似性,主要有4种距离的计算方法(method)有:Jaccard距离、Cosine距离、Euclidean距离和RWMD(Relaxed Word Mover’s Distance)。
sim2(x, y, method):分别计算x和y的相似性;
dist2(x, y, method):跟sim2相反,分别计算x和y距离。
library(text2vec)
data("movie_review")
# 文档向量化
it = itoken(movie_review$review[1:1000], preprocess_function = tolower,tokenizer = word_tokenizer)
v = create_vocabulary(it)
# 删除停用词和低频词
pruned_vocab = prune_vocabulary(v, term_count_min = 10,doc_proportion_max = 0.5, doc_proportion_min = 0.001)
vectorizer = vocab_vectorizer(v)# 创建语料
it1 = itoken(movie_review$review[1:500], preprocess_function = tolower,tokenizer = word_tokenizer)
dtm1 = create_dtm(it1, vectorizer)# 建立文档-词频矩阵
it2 = itoken(movie_review$review[501:1000], preprocess_function = tolower,tokenizer = word_tokenizer)
dtm2 = create_dtm(it2, vectorizer)# 建立文档-词频矩阵
cos_sim <- sim2(x =dtm1, y =dtm2, method = "cosine", norm = "l2")# 生成了一个500*500的相似性矩阵
head(sort(cos_sim[,1], decreasing = TRUE), 10)# 查看第一篇文档与其他文档从大到小前10的相关系数
## 455 85 378 208 227 287 244
## 0.6578019 0.6362218 0.6338216 0.6297589 0.6284934 0.6227449 0.6220061
## 322 497 374
## 0.6194586 0.6186577 0.6167007
3.3 文档-词频矩阵
除了上面的text2vec包里的函数可以构建文档-词频矩阵外,这里还可以用TermDocumentMatrix函数。
data("crude")
tdm <- TermDocumentMatrix(crude, control = list(removePunctuation = TRUE, stopwords = TRUE))
dtm <- DocumentTermMatrix(crude,control = list(weighting =function(x)weightTfIdf(x, normalize =FALSE),stopwords = TRUE))
inspect(tdm[202:205, 1:5])
## <<TermDocumentMatrix (terms: 4, documents: 5)>>
## Non-/sparse entries: 6/14
## Sparsity : 70%
## Maximal term length: 9
## Weighting : term frequency (tf)
## Sample :
## Docs
## Terms 127 144 191 194 211
## companies 1 1 0 0 0
## company 1 0 0 1 0
## companys 0 0 1 0 0
## compared 0 0 0 0 1
inspect(dtm[1:5,202:205])
## <<DocumentTermMatrix (documents: 5, terms: 4)>>
## Non-/sparse entries: 3/17
## Sparsity : 85%
## Maximal term length: 9
## Weighting : term frequency - inverse document frequency (tf-idf)
## Sample :
## Terms
## Docs bbl. beginning benchmark benefits
## 127 0.000000 0 0.000000 0
## 144 0.000000 0 0.000000 0
## 191 3.321928 0 3.321928 0
## 194 6.643856 0 0.000000 0
## 211 0.000000 0 0.000000 0
基于上面处理后的结果,文档-词频矩阵可以用于很多数据挖掘任务,比如:聚类,分类和关联规则。
3.4 频繁项集和关联规则
什么是关联规则?关联规则是形如X→Y的式子,表示通过X可以推导“得到”Y,其中X和Y分别称为关联规则的先导和后继。关联规则挖掘的一个典型例子是啤酒与尿布。通过关联规则挖掘能够发现顾客经常出现同时购买啤酒和尿布的现象。这种关联规则的方向能够帮助卖家了解哪些商品被顾客频繁购买,从而帮助他们开发更好的营销策略。在数据挖掘中,通常用“支持度”和“置性度”两个概念来量化事物之间的关联规则。分别反映所发现规则的有用性和确定性。
对于A->B:
支持度:P(A∩B),所有事件中同时发生A和B的概率。
置信度:P(B|A),在A发生的事件中发生B的概率p(AB)/P(A)。
同时满足最小支持度阈值和最小置信度阈值的规则称为强规则。如果事件A中包含k个元素,那么称这个事件A为k项集,并且事件A满足最小支持度阈值的事件称为频繁k项集。
在挖掘过程中,我们主要是找出所有的频繁项集,然后从频繁项集中产生强规则。
findFreqTerms(tdm, lowfreq=20)# 发现频繁1-项集,频繁项集的阈值为20
## [1] "bpd" "crude" "dlrs" "last" "market" "mln" "oil"
## [8] "opec" "prices" "reuter" "said"
findAssocs(tdm, 'companies', 0.60)# 哪些词和“companies”的关联关系超过0.60
## $companies
## differentials reports march ability opecs
## 0.79 0.79 0.75 0.74 0.73
## markets buyers set meeting however
## 0.72 0.66 0.66 0.65 0.61
## named said two york oil
## 0.61 0.61 0.61 0.61 0.60
这里所用的数据是crude,里面设置频繁项集的阈值是20,频数超过20的单词才认为是频繁项集,而且这里指定项集为1-项集;接着寻找与companies有强关联的单词,这里强关联是指置信度超过0.60的单词,可以看出当companies出现时,set出现的次数最多。
4 聚类
文本聚类是将一个个文档由原有的自然语言文字信息转化成数学信息,以高维空间点的形式展现出来,通过计算点之间的距离比较,将合适的点聚成一个簇,簇的中心叫做簇心。一个好的聚类要保证簇内点的距离小,簇与簇间的距离要远。这里采用kmeans方法聚类。
km <- kmeans(dtm1,5) # k是聚类数
head(km$cluster,10)
## 1 2 3 4 5 6 7 8 9 10
## 2 1 5 2 5 1 1 1 1 1
km$size# 每个类别下有多少条数据
## [1] 302 55 9 17 117
re.km <- list(type=km$cluster)
head(re.km$type,10)# 查看前10条评论的聚类结果
## 1 2 3 4 5 6 7 8 9 10
## 2 1 5 2 5 1 1 1 1 1
聚类后的结果还需要对每个类别进行解释,这里需要对聚类后的每一个类别的内容进行查看再进行总结。
5 词云
“词云”就是对文本中出现频率较高的“关键词”予以视觉上的突出,过滤掉大量的文本信息,只要一眼扫过文本就可以领略文本的主旨。词云制作可以直接采用R里面的wordcloud包,里面有各种词云形状和词颜色。R代码如下:
library(wordcloud2)
library(htmlwidgets)
words <- read.csv("C:\\Users\\test\\Desktop\\唐甜R\\文本分析\\词频统计.csv")
photo <- wordcloud2(words, size = 0.5, shape='cardioid',color = 'random-dark', backgroundColor = "white",fontFamily = "微软雅黑")
换一种形状试试:
photo <- wordcloud2(words, size = 0.4, shape='star')
6 主题模型
主题模型是在文档中发现抽象主题的一种统计模型。如果一篇文章有一个关键思想,那么该关键思想下的一些特定词语会更频繁的出现。但在现实中一篇文章通常包含多种主题,而且每个主题所占比例各不相同。比如某篇新闻在“汽车”主题的比例是60%,“科技”主题的比例是20%,“财经”主题的比例是10%,其他主题的比例是10%。主题模型用数学模型来体现文档的这种特点。主题模型每个文档内的词,根据统计的信息来断定当前文档含有哪些主题,以及每个主题所占的比例各为多少。
dtm = create_dtm(it, vocab_vectorizer(v))
lda_model=LDA$new(n_topics=5)
doc_topic_distr = lda_model$fit_transform(dtm, n_iter = 20)# 查看每篇文档在每个主题上的分布
## INFO [2018-06-17 19:21:24] iter 10 loglikelihood = -1566365.644
## INFO [2018-06-17 19:21:24] iter 20 loglikelihood = -1540653.612
head(doc_topic_distr, 50)
## [,1] [,2] [,3] [,4] [,5]
## 1 0.10502283 0.19863014 0.23744292 0.20091324 0.25799087
## 2 0.25157233 0.16352201 0.10062893 0.17610063 0.30817610
## 3 0.13866667 0.18400000 0.22133333 0.39466667 0.06133333
## 4 0.29473684 0.14210526 0.22368421 0.17105263 0.16842105
## 5 0.22641509 0.17520216 0.28571429 0.22911051 0.08355795
## 6 0.10000000 0.22222222 0.25555556 0.14444444 0.27777778
## 7 0.14159292 0.17699115 0.17699115 0.15929204 0.34513274
## 8 0.26119403 0.12686567 0.16417910 0.17910448 0.26865672
## 9 0.38271605 0.20987654 0.19135802 0.12345679 0.09259259
## 10 0.23255814 0.27906977 0.04651163 0.27906977 0.16279070
## 11 0.24489796 0.16326531 0.14285714 0.34693878 0.10204082
## 12 0.20000000 0.20571429 0.16000000 0.12571429 0.30857143
## 13 0.29336735 0.12755102 0.22704082 0.20663265 0.14540816
## 14 0.15037594 0.22556391 0.10526316 0.24812030 0.27067669
## 15 0.08771930 0.18421053 0.19298246 0.14035088 0.39473684
## 16 0.28421053 0.13684211 0.23157895 0.22631579 0.12105263
## 17 0.21568627 0.31127451 0.11764706 0.23774510 0.11764706
## 18 0.19181034 0.09482759 0.29956897 0.14008621 0.27370690
## 19 0.25819672 0.17622951 0.11885246 0.36885246 0.07786885
## 20 0.14876033 0.19834711 0.25619835 0.21487603 0.18181818
## 21 0.20416667 0.22916667 0.19583333 0.30416667 0.06666667
## 22 0.24285714 0.15000000 0.20357143 0.27857143 0.12500000
## 23 0.17490494 0.19391635 0.23574144 0.30418251 0.09125475
## 24 0.19047619 0.28571429 0.04761905 0.16666667 0.30952381
## 25 0.35000000 0.12500000 0.32500000 0.15000000 0.05000000
## 26 0.17730496 0.18439716 0.15602837 0.19148936 0.29078014
## 27 0.25991189 0.20704846 0.18942731 0.14977974 0.19383260
## 28 0.21544715 0.14634146 0.18292683 0.15040650 0.30487805
## 29 0.19306184 0.25037707 0.13423831 0.12066365 0.30165913
## 30 0.08870968 0.23387097 0.25000000 0.10483871 0.32258065
## 31 0.03773585 0.28301887 0.24528302 0.20754717 0.22641509
## 32 0.17948718 0.13675214 0.22222222 0.25641026 0.20512821
## 33 0.10569106 0.13821138 0.29268293 0.23577236 0.22764228
## 34 0.27575758 0.17878788 0.14242424 0.20606061 0.19696970
## 35 0.11948052 0.18701299 0.38181818 0.09870130 0.21298701
## 36 0.25255973 0.23549488 0.09215017 0.15358362 0.26621160
## 37 0.07971014 0.15217391 0.13043478 0.18840580 0.44927536
## 38 0.22807018 0.14912281 0.35964912 0.14035088 0.12280702
## 39 0.21301775 0.11834320 0.18343195 0.20118343 0.28402367
## 40 0.19744059 0.19012797 0.19561243 0.20292505 0.21389397
## 41 0.26153846 0.30769231 0.11538462 0.24615385 0.06923077
## 42 0.15384615 0.17482517 0.18881119 0.13986014 0.34265734
## 43 0.38582677 0.20472441 0.14173228 0.22834646 0.03937008
## 44 0.17045455 0.23863636 0.11363636 0.19318182 0.28409091
## 45 0.09638554 0.30722892 0.26506024 0.08433735 0.24698795
## 46 0.15126050 0.30252101 0.14285714 0.22689076 0.17647059
## 47 0.16049383 0.24691358 0.14814815 0.25925926 0.18518519
## 48 0.09923664 0.19083969 0.18320611 0.22137405 0.30534351
## 49 0.10077519 0.28294574 0.17441860 0.14341085 0.29844961
## 50 0.19211823 0.19211823 0.14285714 0.09359606 0.37931034