【问题标题】:How to calculate readabilty in R with the tm package如何使用 tm 包计算 R 中的可读性
【发布时间】:2013-02-13 16:31:51
【问题描述】:

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. 使用默认标记器将参数传递到 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)
    

这两个都返回了:

   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") &lt;- y

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

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

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

因此,目前看来,没有预构建的函数来读取与tm 库很好地配合的乐谱。除非有人看到一个简单的错误捕获解决方案,否则我可以将其夹在我的函数调用中以处理无法标记一些明显错误、格式错误的文档?

【问题讨论】:

  • 你不能使用来自 koRpus 的 flesh.kincaid 和来自 tm 的 tm_map 吗?
  • 我好像做不到。它说,“错误:未指定语言!”对于我能想到的tm_map(dd,flesch.kincaid) 的每一个变体,比如tm_map(dd,flesch.kincaid, "en")
  • 所以,我咨询了另一个关于如何将参数传递给嵌套函数的 SO 问题 (stackoverflow.com/questions/6827299/…)。我试过这个tm_map(d,flesch.kincaid,force.lang="en",tagger=tokenize),但得到一个错误,它找不到“指定文件”,然后输出文档1的内容。

标签: r nlp tm


【解决方案1】:

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

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

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

然后我使用tokenize 构造一个kRp.tagged 对象列表,这是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

etc,....所有这些都会产生一个 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 获取包含两个列的数据帧,word(连字符)和 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')))

【讨论】:

  • 这是一个漂亮的答案并且很有帮助,但是如果我所拥有的格式没有像 ovid 文本文件那样存储在本地,我仍然不明白如何进行标记化并将其与 tm 相关联对象。我已经将该库用于其他分析,因此我仍然需要一种方法将 koRpus 可读性分数键入回这些实体,即使我完全为这个算法切换到 koRpus。
  • @Mittenchops 谢谢!好的,在本地没有,但它们在哪里?将 socres 放入 tm 是什么意思。如果分数是通过文档获得的,则很容易将其作为 meta 放入您的 tm 对象中,例如meta(doc[i],'scoree') &lt;- score...
  • 谢谢,@agstudy。我在上面添加了更新。生成语料库的过程比我从中获取它的数据源复杂得多,但我需要往返于这样的格式。阻止我上述最早解决方案的问题是,如果有空白字符串文档,阅读水平分数只会降低它们,我无法正确映射出和返回 tm。 d 以上是我开始的对象。
  • @Mittenchops 我仍然不明白为什么你不能将你的 d
  • 理论上是的...但是您假设这两个软件包必须以连贯的方式一起工作..也许您想要太多?说你可以保存在一个连接(流)中,如果我有更多的时间,我会详细说明..
【解决方案2】:

很抱歉,koRpus 包还没有与 tm 包顺利交互。几个月来,我一直在考虑在两个对象类之间进行转换的方法,但还没有提出真正令人满意的解决方案。如果您对此有任何想法,请随时与我联系。

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

@agstudy:漂亮的图表 :-) 为了节省一些时间,您应该在 readability() 之前运行 hyphen(),这样您就可以通过“连字符”参数重新使用结果。或者您可以在之后简单地访问readability() 结果的“连字符”插槽。如果需要,它会自动断字,并保留结果。仅当您需要在后续步骤之前更改 hyphen() 的输出时,才需要手动调用连字符。我可能会补充一点,0.05-1 在这方面比它的前辈快得多

【讨论】:

  • 我之前没有看到你的评论!我猜你是koRpus 包的作者。 +1!
【解决方案3】:

截至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")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-07
    • 2019-12-12
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    相关资源
    最近更新 更多