R语言 数据挖掘-文本分析(1)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了R语言 数据挖掘-文本分析(1)相关的知识,希望对你有一定的参考价值。
参考技术A 刚接触R语言一周,和matab不同R作用于数据挖掘的库很多,详解见 R语言数据挖掘包
,下面简介文本分析经常使用到的三个包
tm 为文本挖掘提供综合性处理 Rwordmsg 进行中文分词 wordcloud 统计词云
以第三届泰迪杯A题提供的数据集国美-Sheet1进行文本分析 : 第三届泰迪杯
转化为txt的数据集如下图所示:
生成词云:
R语言文本挖掘
点击阅读原文即可获得相应代码和材料。
R语言文本挖掘
• Packages:
tm: 包含了文本挖掘工具;
XML:包含了XML处理工具。
• 下面使用Chapter3中的文件进行分析进行数据分析:
设置工作目录:
> setwd("C:/Users/Mr.Cheng/Desktop/课件/数据科学R语言实战代码/Chapter03")
读取文本文件的路径,然后安装tm包并加载tm包:
> path="state-of-the-union.txt"
> install.packages("tm")
> library(tm)
通过下列代码将其分成块或行:
> text=readLines(path,encoding="UTF-8")
text是变量声明中行的数组。有若干可用的文本函数,可以直接在结果的文本中运行,常用的操作包括以下几项。
1. 转换成小写字母;
2. 移除标点;
3. 移除数字:此操作用于集中涉及具体的文本;
4. 移除URL:此操作可以避免使出现在URL中的字复杂化;
5. 调整“停用词”列表:当与特定行业的文本一起工作时,此操作尤其有用;
6. 与词干一起工作:此操作允许调整文本以便仅出现词干。有助于将焦点集中于文本中涉及的真正术语,并非出现的各种格式。
R使用了用于处理文本的语料库。可以从多种源创建语料库,源包括VecyorSource(文本流)。下列代码会将原始文本转化为语料库,便于进一步进行R处理:
> vs=VectorSource(text)#将文本与出现在源中单词的向量排成一行
> elem=getElem(stepNext(vs))#getElem()函数建立了已通过的源,用于R中进行更深的数据存取。stepNext()函数更新了源的位置,以备将来之需。
> result=readPlain(elem,"en","id1")
> txt=Corpus(vs) #Corpus():语料库是一些可用于进一步处理的数据源
• 创建语料库:
• 将文本转化成小写字母:
> txtlc=tm_map(txt,tolower)
> inspect(txt[1])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] Mr. Speaker, Mr. Vice President, Members of Congress, my fellow Americans:
> inspect(txtlc[1])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] mr. speaker, mr. vice president, members of congress, my fellow americans:
• 移除标点:
> txtnp=tm_map(txt,removePunctuation) > inspect(txt[1]) <<SimpleCorpus>> Metadata: corpus specific: 1, document level (indexed): 0 Content: documents: 1 [1] Mr. Speaker, Mr. Vice President, Members of Congress, my fellow Americans: > inspect(txtnp[1]) <<SimpleCorpus>> Metadata: corpus specific: 1, document level (indexed): 0 Content: documents: 1 [1] Mr Speaker Mr Vice President Members of Congress my fellow Americans |
• 移除数字:
> txtnn=tm_map(txtnp,removeNumbers)
> inspect(txtnp[63])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] After 2014 we will ······
> inspect(txtnn[63])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] After we will ······
• 移除单词:
通常移除所有短的英语单词,这些单词对分析没有意义,通常都会移除停用词以便停止作者对单词赋予的特殊含义。“the”和“and”就是停用词,虽然是必须用词,但是这些单词并不会提升文本的质量。可仅通过向集群添加停用词,调整感兴趣的语言中的标准停用词。
> txtns=tm_map(txt[1],removeWords,stopwords("english"))
> inspect(txtns)
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] Mr. Speaker, Mr. Vice President, Members Congress, fellow Americans:
> inspect(txt[1])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] Mr. Speaker, Mr. Vice President, Members of Congress, my fellow Americans:
• 移除空格符
移除空格符与标准的文本挖掘的关系不大,并且使用的函数会忽视先前的空格符。此函数提供了一种清除中间结果以便于进行更好说明的方法:
> txtnw=tm_map(txt[30],stripWhitespace)
> inspect(txtnw)
> inspect(txt[30])
*stripWhitespace 同时也将标点从两个拓展字符减少到一个拓展字符。
• 词干
我们可以将语料库调整自仅使用词干。词干是词根,而不管通用的屈折词缀或用法。例如,“wait”“waiting”“waits”“waited”等词的词干相同。
> install.packages("SnowballC")
> inspect(txt[50])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] A pre-existing condition used to mean that someone like Amanda Shelley, a physician assistant and single mom from Arizona, couldn’t get health insurance.? But on January 1st, she got covered.? On January 3rd, she felt a sharp pain.? On January 6th, she had emergency surgery.? Just one week earlier, Amanda said, that surgery would’ve meant bankruptcy.
> txtstem=tm_map(txt,stemDocument)
> inspect(txtstem[50])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
[1] A pre-exist condit use to mean that someon like Amanda Shelley, a physician assist and singl mom from Arizona, couldn’t get health insurance.? But on Januari 1st, she got covered.? On Januari 3rd, she felt a sharp pain.? On Januari 6th, she had emerg surgery.? Just one week earlier, Amanda said, that surgeri would’v meant bankruptcy.
> txtcomplete=tm_map(txtstem,stemCompletion,dictionary=txt)
> inspect(txtcomplete[50])
<<SimpleCorpus>>
Metadata: corpus specific: 1, document level (indexed): 0
Content: documents: 1
A pre-exist condit use to mean that someon like Amanda Shelley, a physician assist and singl mom from Arizona, couldn’t get health insurance.? But on Januari 1st, she got covered.? On Januari 3rd, she felt a sharp pain.? On Januari 6th, she had emerg surgery.? Just one week earlier, Amanda said, that surgeri would’v meant bankruptcy.
• 文档词条矩阵
文本词条矩阵表示术语出现在一些文档中的频率,所以,每个文档都包括某一术语在该文档中的次数。在我们的示例中,此矩阵包括文档行/段中发现的关键词以及出现的频率。
> dtm=DocumentTermMatrix(txt)
DocumentTermMatrix(x,control=) #表示语料库中的术语用法;
#x:语料库。
#control:控制选项的名单。某些选项特定于进一步使用。可用于全局选项#有以下两项:
1. bounds:使用的语料库范围。
2. weighting:包含了用于遇到过的术语的加权函数。
> dtm
<<DocumentTermMatrix (documents: 86, terms: 1763)>>
Non-/sparse entries: 4521/147097
Sparsity : 97%
Maximal term length: 16
Weighting : term frequency (tf)
> txt=tm_map(txt,removeWords,stopwords("English"))
#tm_map(x,FUN,……,lazy=T)将转换用于语料库界面:
1. x:使用转换的语料库;
2. FUN:需要使用的转换;
3. lazy:如果设置为TRUE, 可执行惰性数据存取。
removewords会删除文档中的字;
stopwords集是通用的英语停用词列表;
removeSparseTerm功能可以为文档矩阵删除不经常遇到的术语:removeSparseTerms(x,sparse),其中x为一个语料库,sparse为包含所允许的最大稀疏性的值,范围为0~1.
findAssocs(x,terms,corlimit): 用来找到文档矩阵中词语的关联,其中terms 为我们必须找到其关联性的术语,corlimit为包含所要探索的较低相关性限制。
我们同样可以使用tm包中的函数移除稀疏术语以降低矩阵的稀疏性。
> dtm2=removeSparseTerms(dtm,0.94)
> inspect(dtm2)
<<DocumentTermMatrix (documents: 86, terms: 146)>>
Non-/sparse entries: 1956/10600
Sparsity : 84%
Maximal term length: 11
Weighting : term frequency (tf)
Sample :
Terms
Docs and but for have more our that the this with
10 5 1 2 0 1 1 2 8 5 0
21 8 0 0 0 3 4 4 10 1 1
26 6 2 0 1 3 4 0 8 0 5
37 7 1 3 0 3 2 0 4 1 3
39 3 1 1 1 1 2 2 5 2 2
40 12 0 0 0 5 2 4 7 0 3
48 4 1 5 2 1 0 4 8 2 2
66 6 1 3 0 1 4 1 11 2 2
72 11 1 1 2 0 3 1 8 0 2
83 10 3 4 1 1 9 2 5 0 1
我们可以寻找不同单词之间的关联:
> findAssocs(dtm2,"work",0.25)
$work
together hard most and want
0.52 0.47 0.46 0.45 0.45
make can the all americans
0.43 0.43 0.42 0.38 0.37
for are let’s help but
0.37 0.36 0.36 0.35 0.35
nation take way other more
0.35 0.35 0.35 0.33 0.32
where believe future like opportunity
0.32 0.31 0.31 0.31 0.31
what families who that young
0.31 0.31 0.29 0.29 0.29
last workers this right i’m
0.29 0.28 0.27 0.27 0.27
see while new some create
0.27 0.27 0.26 0.26 0.26
don’t
0.26
看来奥巴马希望美国民众一起努力的工作。
• 文本集群
在我们努力进行集合的数值分析中,通常会使用聚类,如以通用性为基础的观测或观测数据点的接近。在文本分析中,我们使用聚类重复同样的操作:试图确定文档中单词用法之间的关系。
在本例中,我们使用K-means聚类。K-means聚类减少了关系式之间的平方差和以及距离被最小化到规定的阈值的群组/集群字。在这种情况下,即为规定集群的数目。
> library(stats)
> mymeans=kmeans(dtm,5)
> mymeans
K-means clustering with 5 clusters of sizes 9, 6, 29, 8, 34
Cluster means:
americans congress fellow members president
speaker vice america america’s and
decades did extra graduation her
highest its level lift more
needed part rate spent student
······
[ reached getOption("max.print") -- omitted 5 rows ]
Clustering vector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
5 5 5 5 3 5 4 5 4 4 5 3 3 1 4 5 5 3 3 3
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
2 5 1 5 3 2 1 5 3 3 5 5 4 3 5 5 1 5 1 2
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
3 3 5 3 3 3 3 4 5 5 5 5 5 5 3 3 5 3 3 3
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
3 1 3 1 1 4 2 3 3 4 3 2 3 3 1 5 5 5 5 3
81 82 83 84 85 86
5 5 2 5 5 5
Within cluster sum of squares by cluster:
[1] 821.1111 780.3333 2095.3103 875.6250 963.2059
(between_SS / total_SS = 23.4 %)
Available components:
[1] "cluster" "centers" "totss"
[4] "withinss" "tot.withinss" "betweenss"
[7] "size" "iter" "ifault"
看一下汇总数据,你会发现我们要删除的稀疏项(8815个中心)
> summary(mymeans)
Length Class Mode
cluster 86 -none- numeric
centers 8815 -none- numeric
totss 1 -none- numeric
withinss 5 -none- numeric
tot.withinss 1 -none- numeric
betweenss 1 -none- numeric
size 5 -none- numeric
iter 1 -none- numeric
ifault 1 -none- numeric
我们还可以找到用得罪频繁的术语(至少被提及十次)(含停用词,如“.”“和”等):
> freq=findFreqTerms(dtm,10)
> freq
[1] "americans" "congress" "america" "and"
[5] "more" "than" "time" "today"
[9] "who" "with" "businesses" "have"
[13] "jobs" "new" "our" "over"
[17] "the" "years" "help" "his"
[21] "some" "world" "but" "first"
[25] "for" "from" "give" "home"
······
我们可以绘制集群的树枝形结构关系图来表明关系:
> m2=as.matrix(dtm)
> dm=dist(scale(m2))
> fit=hclust(dm,method="ward.D")
> plot(fit)
• 文字图形
> source("http://bioconductor.org/biocLite.R")
> biocLite("Rgraphviz")
#这个包非常难以安装,具体参见:http://blog.csdn.net/weidelight/article/details/42100795 和https://wiki.duke.edu/display/DUKER/Install+RGraphviz+under+Windows
> library(Rgraphviz)
> path1="Detailed Description of Documents Available.txt"
> text1=readLines(path1,encoding="UTF-8")
> vs=VectorSource(text1)
> elem=getElem(stepNext(vs))
> result=readPlain(elem,"en","id1")
> txt1=Corpus(vs)
> dtm1=DocumentTermMatrix(txt1)
> plot(dtm1,terms=findFreqTerms(dtm1,lowfreq=5)[1:10],corThreshold=0.5)
我们可以通过使用R看见常用词的条形图(计数超过10):
> tdm=TermDocumentMatrix(txt1)
#注意这里的是TermDocumentMatrix
> m=as.matrix(tdm)
# 转换为矩阵
> v=sort(rowSums(m),decreasing=T)
# 按行求和生成得到每个单词的频数
> d=data.frame(word=names(v),freq=v)
# 进一步转换为data.frame便于调用
> library(ggplot2)
> q=ggplot(subset(d,freq>10),aes(word,freq))+geom_bar(stat="identity")+theme(axis.text.x=element_text(angle=45,hjust=1))
> q
生成词云:
> library(wordcloud2)
> wordcloud2(d,minRotation = -pi/2,maxRotation = pi/2,size=2)
调整配色:
用RColorBrewer包中的brewer.pal来选择适合的调色板:
> install.packages("RColorBrewer")
> library(RColorBrewer)
> display.brewer.all()
#查看所有的配色
> brewer.pal(7,"YlOrRd")
[1] "#FFFFB2" "#FED976" "#FEB24C" "#FD8D3C" "#FC4E2A" "#E31A1C"
[7] "#B10026"
> display.brewer.pal(7,"YlOrRd")
> wordcloud2(d,minRotation = -pi/2,maxRotation = pi/2,size=1.2,color=pal)
> pal=brewer.pal(6,"Dark2")
> pal=pal[-(1:6)]
> wordcloud2(d,minRotation = -pi/2,maxRotation = pi/2,size=1,color=pal)
• 分析XML文本
将XML数据输入R中:
> library(XML)
> url="books.xml"
> data=xmlParse(url)
判断XML功能包按所需方式及时间工作。由于源XML文件可能较大,只有在发出要求时函数才会输入大量数据。你会发现此时数据对象中没有内容。
判断XML功能包是否已对全部XML流进行解析,并将其转换为列表:
> df=xmlToDataFrame(data)
查看列表的第一行:(我们可以获取栏标题)
> colnames(df)
[1] "author" "title" "genre" "price" "publish_date"
[6] "description"
这时我们会得到一个一致的XML,因此XML已被转换为数据框比如,我们可以通过以下代码计算平均图书价格:
> mean(as.numeric(df$price))
[1] 3.416667
还有一个有趣的现象,即数据不一致,且不易转换为数据框。下面示例中使用的是华盛顿大学的课程列表uwm.xml文件:
当XML工作时,我们需要移至文档中的实际数据进行操作。这一步骤可以通过以下文档根实现:
> url="uwm.xml"
> data=xmlParse(url)
> root=xmlRoot(data)
在这一点上,直接将根绘制在XML上。我们所拥有根域所提供的主题集合如下第一课程设置的显示所示。
> root[1]
$course_listing
<course_listing>
<note>#</note>
<course>216-088</course>
<title>NEW STUDENT ORIENTATION</title>
<credits>0</credits>
<level>U</level>
······
attr(,"class")
[1] "XMLInternalNodeList" "XMLNodeList"
可获得一张出现在每个XML节点的字段列表:
> fields=xmlApply(root,names)
> fields
$course_listing
note course title credits
"note" "course" "title" "credits"
level restrictions section_listing
"level" "restrictions" "section_listing"
······
所以,不出所料,每一类别都有注释、标题等内容。通过查看数据可以看见各种section_listing条目,这取决于某一特定科目有多少章节。section_listing 条目是全新的子树,因此此条目在之前的代码在之前的代码案例的引文中出现。
可以通过检查XML的显著性差异:
> table(sapply(fields,identical,fields[[1]]))
FALSE TRUE
1779 333
300多个科目似乎有若干个章节。这样就会阻止我们将XML树搬至矩阵和/或数据框中,原因在于每个节点的数据并非一致。
可确保有正确的字段列表(并非像之前那样粗略地看):
> unique(unlist(fields)) [1] "note" "course" "title" "credits" [5] "level" "restrictions" "section_listing" |
所以希望按照某一方式对所有的数据进行分类。课程中有哪些不同的等级?请找出它们:
> unique(xpathSApply(data,"//*/level",xmlValue))
[1] "U" "G" "U/G"
从XML提取信息的标准机制是使用路径。路径说明了希望采取的方向,从作为起点的节点一直到下面记忆中特定的测试:
就之前的指令来说,我们告诉R从数据或XML文档的最基本内容开始。从那里起下降了两个等级(第一等级是文档的基本内容,第二等级是course_listing)。应该能够跟随之前样例输出的路径。然后,寻找水平字段的示例。水平字段的每个数值都会放入结果中。所有的结果都会放入唯一性测试,并且在屏幕上显示输出。
什么是等级的拆分?R中的标准技术就是采用路径中发现的原始数值,并且将这些数值添加到表中。由于将数值添加到表中之后可以发现相同的数值,因此会扩展简易计数器:
> table(xpathSApply(data,"//*/level",xmlValue))
G U U/G
511 1154 447
其中G为研究生,U为本科生。
哪些讲师授课最多:
> instructors=table(xpathSApply(data,"//*/instructor",xmlValue))
> instructors
Abler Aborampah
1 3
Abu-Zahra, H. Abu-Zahra, N.
1 2
Abu Khodair Acad Staff
1 296
······
> which.max(instructors)
TA
1108
> which.min(instructors)
Abler
3
哪些课程包含的章节最多?
> sections=table(xpathSApply(data,"//*/section_listing",xmlValue))
> sections
> which.max(sections)
Se 101To be ArrangedFaculty
3739
> which.min(sections)
#eLa 801MW4:30pm7:00pmART78GundermanADD'L SPECIAL COURSE FEE: $ 50.00
1
查看不同学科的学分:
> credits=table(xpathSApply(data,"//*/credits",xmlValue))
> credits
0 0-1 0@ 1 1-12 1-2 1-3 1-4 1-5 1-5H 1-6 1-9 1-9H 1@ 12
4 2 2 233 84 12 84 27 1 1 51 7 2 16 1
1H 1or2 2 2-10 2-12 2-3 2-4 2-6 2or3 2or4 3 3-4 3-5 3-6 3@
1 5 182 1 2 22 9 7 8 1 1204 1 3 8 1
3H 3or4 3or6 4 5 6 8 9
10 2 9 76 8 23 1 1
> xpathSApply(data,"//*[credits=12]",xmlValue)
[1] "+930-401THERAPEUTIC RECREATION INTERNSHIP AND SEMINAR12U; ; PREREQ: MUST HAVE COMPLETED ALL COURSE WORK IN THE THERREC MAJORSe 001W9:00am10:40amEND953Thomas"
展示生成的学分表时,我们会发现大量科目都对应着一系列的学分(credits)。同时可以看到海量的数据中存在着一个标准问题,不良数据,如0@credits。
其中有一个科目是12个学分,对此,我们可以通过不太一样的方法进行查找。我们可以再次下移两个等级,找到学分字段,查找数值12.然后,所查找的内容就会以应用函数的形式全部呈现出来。
以上是关于R语言 数据挖掘-文本分析(1)的主要内容,如果未能解决你的问题,请参考以下文章