如何使用tm包计算R中的可读性

时间:2013-02-13 16:31:52

标签: r nlp tm

tm库中是否有预先构建的函数,或者与它一起使用的函数?

我当前的语料库被加载到tm中,如下所示:

s1 <- "This is a long, informative document with real words and sentence structure:  introduction to teaching third-graders to read.  Vocabulary is key, as is a good book.  Excellent authors can be hard to find." 
s2 <- "This is a short jibberish lorem ipsum document.  Selling anything to strangers and get money!  Woody equal ask saw sir weeks aware decay. Entrance prospect removing we packages strictly is no smallest he. For hopes may chief get hours day rooms. Oh no turned behind polite piqued enough at. "
stuff <- rbind(s1,s2) 
d <- Corpus(VectorSource(stuff[,1]))

我尝试使用koRpus,但在与我已经使用的软件包不同的软件包中进行重新标记似乎很愚蠢。我也有一些问题,它会以一种允许我将结果重新纳入tm的方式对其返回对象进行矢量化。 (也就是说,由于错误,它通常会返回比我的集合中的文档数量更多或更少的可读性分数。)

我知道我可以做一个天真的计算,将元音解析为音节,但想要一个更彻底的包来处理边缘情况(解决静音e等)。

我的可读性分数是Flesch-Kincaid或Fry。

我最初尝试过的地方,其中d是我的100份文件的语料库:

f <- function(x) tokenize(x, format="obj", lang='en')
g <- function(x) flesch.kincaid(x)
x <- foreach(i=1:length(d), .combine='c',.errorhandling='remove') %do% g(f(d[[i]]))

不幸的是,x返回的文档少于100个,因此我无法将成功与正确的文档相关联。 (这部分是我对R中'foreach'与'lapply'的误解,但我发现文本对象的结构足够困难,我无法正确地标记,应用flesch.kincaid,并以合理的顺序成功检查错误语句。)

更新

我尝试过另外两件事,尝试将koRpus函数应用于tm对象......

  1. 使用默认的tokenizer将参数传递给tm_map对象: tm_map(d,flesch.kincaid,force.lang="en",tagger=tokenize)

  2. 定义一个标记生成器,将其传入。

     f <- function(x) tokenize(x, format="obj", lang='en')
     tm_map(d,flesch.kincaid,force.lang="en",tagger=f)
    
  3. 这两个都返回了:

       Error: Specified file cannot be found:
    

    然后列出d [1]的全文。好像找到了吗?我该怎么做才能正确传递函数?

    更新2

    这是我尝试使用lapply直接映射koRpus函数时出现的错误:

    > lapply(d,tokenize,lang="en")
    Error: Unable to locate
     Introduction to teaching third-graders to read.  Vocabulary is key, as is a good book.  Excellent authors can be hard to find. 
    

    这看起来像一个奇怪的错误---我几乎不认为这意味着它无法找到文本,但是在转储之前它找不到一些空白的错误代码(例如'tokenizer')找到的文字。

    更新3

    使用koRpus重新标记的另一个问题是,重新标记(与tm标记符相比)非常慢,并将其标记化进度输出到标准输出。无论如何,我尝试了以下内容:

    f <- function(x) capture.output(tokenize(x, format="obj", lang='en'),file=NULL)
    g <- function(x) flesch.kincaid(x)
    x <- foreach(i=1:length(d), .combine='c',.errorhandling='pass') %do% g(f(d[[i]]))
    y <- unlist(sapply(x,slot,"Flesch.Kincaid")["age",])
    

    我的目的是将上面的y对象重新绑定回我的tm(d)语料库作为元数据meta(d, "F-KScore") <- y

    不幸的是,应用于我的实际数据集,我收到错误消息:

    Error in FUN(X[[1L]], ...) : 
      cannot get a slot ("Flesch.Kincaid") from an object of type "character"
    

    我认为我的实际语料库中的一个元素必须是NA,或者太长,还有其他令人望而却步的元素 - 并且由于嵌套的功能化,我无法准确地追踪它是什么。

    因此,目前看起来没有预先构建的功能来读取与tm库很好地配合的分数。除非有人看到一个简单的错误捕获解决方案,否则我可以将其置于函数调用中以处理无法对某些明显错误的格式错误的文档进行标记的问题?

3 个答案:

答案 0 :(得分:4)

您收到错误,因为koRpus函数无法处理corpus个对象。最好创建一个kRp.tagged对象,然后在其上应用所有koRpus个功能。在这里,我将使用ovid包的tm数据来说明我是如何做到这一点的。

我使用list.files来获取源文件列表。您只需要为源文本文件提供正确的路径。

ll.files <- list.files(path = system.file("texts", "txt", 
                                    package = "tm"),
                 full.names=T)

然后我使用kRp.tagged构建tokenize对象列表,这是koRpus包提供的默认标记符(建议使用TreeTagger但是你需要安装它)

ll.tagged <- lapply(ll.files, tokenize, lang="en") ## tm_map is just a wrapper of `lapply`

一旦我有了“标记”对象列表,我就可以在其上应用可读性公式。由于flesch.kincaidreadability的包装,我将直接应用后者:

ll.readability <- lapply(ll.tagged,readability)          ## readability
ll.freqanalysis <- lapply(ll.tagged,kRp.freq.analysis)   ## Conduct a frequency analysis
ll.hyphen <- lapply(ll.tagged,hyphen)                    ## word hyphenation

等,....所有这些都会产生一个S4对象列表。 desc广告位可让您轻松访问此列表:

lapply(lapply(ll.readability ,slot,'desc'),              ## I apply desc to get a list
         '[',c('sentences','words','syllables'))[[1]]    ## I subset to get some indexes
[[1]]
[[1]]$sentences
[1] 10

[[1]]$words
[1] 90

[[1]]$syllables
all  s1  s2  s3  s4 
196  25  32  25   8 

例如,您可以使用插槽hyphen来获取包含两个列,单词(带连字符的单词)和syll(音节数)的数据框。在这里,使用lattice,绑定所有data.frames,为每个文档绘制dotplot

library(lattice)
ll.words.syl <- lapply(ll.hyphen,slot,'hyphen')     ## get the list of data.frame
ll.words.syl <- lapply(seq_along(ll.words.syl),      ## add a  column to distinguish docs
       function(i)cbind(ll.words.syl[[i]],group=i))
dat.words.syl <- do.call(rbind,ll.words.syl)
dotplot(word~syll|group,dat.words.syl,
        scales=list(y=list(relation ='free')))

enter image description here

答案 1 :(得分:3)

我很抱歉koRpus包没有顺利地与tm包交互。几个月来我一直在考虑在两个对象类之间进行转换的方法,但还没有找到一个非常令人满意的解决方案。如果您有这方面的想法,请不要犹豫与我联系。

但是,我想向您推荐koRpus生成的可读性对象的summary()方法,该方法返回精简的data.frame相关结果。这可能比通过相当复杂的S4对象的替代爬行更容易访问;-)您也可以尝试summary(x, flat=TRUE)

@agstudy:好图:-)为节省时间,您应该在hyphen()之前运行readability(),这样您就可以通过“连字符”参数重复使用结果。或者您可以稍后访问readability()结果的“连字符”插槽。如果需要,它将自动连字,并保留结果。只有在下一步之前需要更改hyphen()的输出时,才需要手动调用连字符。我可能会补充说,0.05-1比其前辈更快

答案 2 :(得分:2)

qdap version 1.1.0开始,qdap的number of functions与tm包更加兼容。这是一种使用您提供的相同Corpus来解决问题的方法(注意Fry最初是一个图形测量,qdap保留了这个;也通过你的语料库和随机抽样Fry建议你的样本语料库不是大到足以计算Fry的):

library(qdap)
with(tm_corpus2df(d), flesch_kincaid(text, docs))

##   docs word.count sentence.count syllable.count FK_grd.lvl FK_read.ease
## 1   s1         33              1             54       16.6       34.904
## 2   s2         49              1             75       21.6       27.610

with(tm_corpus2df(d), fry(text, docs))

## To plot it
qheat(with(tm_corpus2df(d), flesch_kincaid(text, docs)), values=TRUE, high="red")

enter image description here