从标签向量列表创建一个标签频率数据框。

6
我正在编写一个在R中找到书面语统计(一种语言度量)的函数,用于分析打字对话。我使用openNLP的词性标注器来标记单词(这是一个很棒的工具,但速度有点慢,因为它在进行一些繁重的处理)。无论如何,时间已经成为了这个函数的一个问题,而且我遇到了一个问题,我希望能够尽快解决。我开始思考复杂的术语,知道我需要一些集体思考来解决这个问题。
我有一个包含标签的向量列表,像这样:
G 
[[1]]
[1] "MD"  "DT"  "NN"  "VB"  "VBG" "TO"  "POS"

[[2]]
[1] "DT" "NN" "JJ" "RB"

[[3]]
[1] "RB"  "TO"  "PRP"

[[4]]
[1] "VBZ" "PRP" "VBG" "RB"  "TO"  "NN" 

[[5]]
[1] "NN" "NN"

对于每个向量,我想要统计所有可能标签出现的频率(如果向量不包含标签,则插入零),并生成以下数据框结构:

  DT  JJ  MD  NN  POS PRP RB  TO  VB  VBG VBZ
1  1   0   1   1    1   0  0   1   1    1   0
2  1   1   0   1    0   0  1   0   0    0   0
3  0   0   0   0    0   1  1   1   0    0   0
4  0   0   0   1    0   1  1   1   1    1   1
5  0   0   0   2    0   0  0   0   0    0   0

以下是我对于这个问题的初步思考以及虚拟数据集。我最初想使用表格,但不确定是否可行,因为我知道这比使用rle、match或索引[要慢。我也考虑过在这些向量上使用Reduce和merge进行多重合并,但是我知道R中的高阶函数可能比其他方法慢(也许可以通过一些好的索引来完成)。无论如何,我非常希望在这个问题上得到帮助。我寻找的两个参数是:
1.基础解决方案 2.速度
数据和我的初步想法(表格可能不是正确的方法):
G <- list(c("MD", "DT", "NN", "VB", "VBG", "TO", "POS"), c("DT", "NN", 
"JJ", "RB"), c("RB", "TO", "PRP"), c("VBZ", "PRP", "VBG", "RB", 
"TO", "NN"), c("NN", "NN"))

P <- lapply(G, function(x) table(sort(x)))  #to get frequencies on each word
sort(unique(names(unlist(P))))  #to get the column names and number

抱歉,该主题名称很难归类。
编辑:(添加基准测试结果)
非常有创意的答案。我没有想到因子解决方案和指定级别。聪明。对于速度,Joran的第二个答案最快(我只是使用你已经创建的lev回加了列名)。mdsummer的响应是代码最少的,与速度并列第二。我会选择Joran的第二个答案,因为它可以给我最好的速度提升。谢谢大家!非常感激 :) 比较结果可在gist上查看https://gist.github.com/trinker/91802b8c4ba759034881
       expr        min         lq      mean     median        uq       max neval
   JORAN1()  648.04435  689.16756  714.9142  712.59122  732.4991  831.6623   100
   JORAN2()   86.83879   92.91911   98.7068   97.44690  101.6764  177.4228   100
   RINKER()   87.40797   94.07564  100.1154   98.39624  104.0887  177.3146   100
      TIM()  900.65847  964.23419  993.9475  988.89306 1023.0587 1137.6263   100
 MDSUMMER() 1395.95920 1487.45279 1527.3181 1527.92664 1571.0997 1685.3298   100

1
对于标题,我会将“sums”替换为“frequencies”。 - flodel
@flodel 好的,已完成。 - Tyler Rinker
参考splitstackshape:::charMat,可以轻松重写它来处理这个问题。我正在“splitstackshape”的“stringi”分支中进行实验。 - A5C1D2H2I1M1N2O1R2T1
1
你不想加上 qdapTools::mtabulate(G) 吗?这样我们就可以将其作为规范的重复内容了。 - David Arenburg
@DavidArenburg 我做了这道题,但是我指定了一个基本方法 :( 也许可以开放任何解决方案?? - Tyler Rinker
4个回答

5
我会这样做:

我会这样做:

lev <- sort(unique(unlist(G)))

G1 <- do.call(rbind,lapply(G,function(x,lev){ table(factor(x,levels = lev,
                                                     ordered = TRUE))},lev = lev))

     DT JJ MD NN POS PRP RB TO VB VBG VBZ
[1,]  1  0  1  1   1   0  0  1  1   1   0
[2,]  1  1  0  1   0   0  1  0  0   0   0
[3,]  0  0  0  0   0   1  1  1  0   0   0
[4,]  0  0  0  1   0   1  1  1  0   1   1
[5,]  0  0  0  2   0   0  0  0  0   0   0

或者为了更快(但是失去列名):

G1 <- do.call(rbind,lapply(G,function(x,lev){ tabulate(factor(x,levels = lev,
                                ordered = TRUE),nbins = length(lev))},lev = lev))

4
我认为这可以满足您的需求,只需获取所有独特值的完整列表作为factor levels,然后根据每个向量作为该因素的实例进行制表。接着您可以通过使用do.call将整个过程包装起来,并将各行绑定在一起。
levs <- sort(unique(names(unlist(P))))

do.call("rbind", lapply(G, function(x) table(factor(x, levs))))

那个使用因子的方法很聪明 :) +1 - Tyler Rinker
这是一件棘手的事情,你比我慢了7秒钟,我不确定你使用有序是否重要,可能需要额外小心处理NA值。 - mdsumner
@mdsumner,我尝试了一个包含NA的数据集,所有4个代码都表现良好,在该行的所有列中都给出了0。 - Tyler Rinker
我只是使用了ordered来确保结果与Tyler的匹配。可能并不需要... - joran

2
也许使用qdapToolsmtabulate函数能够更快地实现此处功能:
library(qdapTools)
mtabulate(G)

##   DT JJ MD NN POS PRP RB TO VB VBG VBZ
## 1  1  0  1  1   1   0  0  1  1   1   0
## 2  1  1  0  1   0   0  1  0  0   0   0
## 3  0  0  0  0   0   1  1  1  0   0   0
## 4  0  0  0  1   0   1  1  1  0   1   1
## 5  0  0  0  2   0   0  0  0  0   0   0

1

这将会得到你想要的结果,但不知道它是否足够快:

    G <- list(c("MD", "DT", "NN", "VB", "VBG", "TO", "POS"), c("DT", "NN", 
            "JJ", "RB"), c("RB", "TO", "PRP"), c("VBZ", "PRP", "VBG", "RB", 
            "TO", "NN"), c("NN", "NN"))
    Tags <- sort(unique(unlist(G)))

    t(vapply(G,function(x){
        a <- Tags %in% x
        a[a] <- tapply(x %in% Tags,x,sum)
        a
    }, FUN.VALUE = rep(0,length(Tags))))

         DT JJ MD NN POS PRP RB TO VB VBG VBZ
    [1,]  1  0  1  1   1   0  0  1  1   1   0
    [2,]  1  1  0  1   0   0  1  0  0   0   0
    [3,]  0  0  0  0   0   1  1  1  0   0   0
    [4,]  0  0  0  1   0   1  1  1  0   1   1
    [5,]  0  0  0  2   0   0  0  0  0   0   0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接