【问题标题】:Term Document Matrix for Letters in RR中字母的术语文档矩阵
【发布时间】:2015-10-26 01:48:38
【问题描述】:

我想构建一个 n-gram '字母文档矩阵',它基本上使用最多 n 个字母的字母序列,而不是典型的单词。这是我想要实现的简化示例:

> letterDocumentMatrix(c('ea','ab','ca'), c('sea','abs','cab'))
    [,sea] [,abs] [,cab]
[ea,] TRUE   FALSE  FALSE  
[ab,] FALSE  TRUE   TRUE   
[ca,] FALSE  FALSE  TRUE

这种操作有名称吗?是否有任何预构建的函数可以处理这个问题?

最后,我用 grepl 尝试了 outer,但无济于事:

> outer(c('ea','ab','ca'), c('sea','abs','cab'), grepl)
          [,1]  [,2]  [,3]
     [1,] TRUE  FALSE FALSE  
     [2,] TRUE  FALSE FALSE
     [3,] TRUE  FALSE FALSE  
     Warning message:
     In FUN(X, Y, ...) :
       argument 'pattern' has length > 1 and only the first element will be used

似乎外部将整个第一个参数传递给 grepl,而不是一次一个条目,导致 grepl 只搜索第一个术语,在这种情况下是 'a'。

【问题讨论】:

    标签: r nlp grepl


    【解决方案1】:

    grepl() 没有通过其pattern 参数进行矢量化,这就是为什么您没有从outer() 获得正确结果的原因。这是使用vapply() 的可能解决方案。

    vec <- c("sea", "abs", "cab") ## vector to search
    pat <- c("ea", "ab", "ca")    ## patterns we are searching for
    "rownames<-"(vapply(pat, grepl, NA[seq_along(pat)], vec, fixed = TRUE), vec)
    #        ea    ab    ca
    # sea  TRUE FALSE FALSE
    # abs FALSE  TRUE FALSE
    # cab FALSE  TRUE  TRUE
    

    这显然会导致您想要的转换版本。为了得到你想要的矩阵,我们可以使用lapply()rbind()的结果,然后设置名称。

    xx <- do.call(rbind, lapply(pat, grepl, x = vec, fixed = TRUE))
    dimnames(xx) <- list(pat, vec)
    #      sea   abs   cab
    # ea  TRUE FALSE FALSE
    # ab FALSE  TRUE  TRUE
    # ca FALSE FALSE  TRUE
    

    我会说在vapply() 结果上使用t() 来转置它,但在大型矩阵上可能会很慢。

    【讨论】:

    • `rownames&lt;-`(sapply(pat, grepl, x=src), src) 如果你想变得花哨,使用pat 作为patternsrc 作为搜索向量。
    • 谢谢!顺便说一句,lapply 中的 fixed = TRUE 选项有什么作用?
    • @JP_smasher - 它告诉grepl 避免检查正则表达式引擎中的模式,因为我们正在寻找一个固定的模式。这通常会使事情变得更快。
    【解决方案2】:

    我们可以Vectorizeouter 中的乐趣

    outer(c('ea','ab','ca'), c('sea','abs','cab'), Vectorize(grepl))
    #     [,1]  [,2]  [,3]
    #[1,]  TRUE FALSE FALSE
    #[2,] FALSE  TRUE  TRUE
    #[3,] FALSE FALSE  TRUE
    

    【讨论】:

    • 谢谢!这可行,但在较大的数据集上有点慢
    【解决方案3】:

    quanteda 包中有一个预构建的函数可以处理此问题,用于文本分析,这将涉及您将字母序列视为“字典:正则表达式并构建文档特征矩阵,其中这些正则表达式在每个“文档”中都有标识。通过使用字典整理对 dfm() 函数的调用,您将获得确切的返回对象。在这里,我已将其转换为您的问题。

    letterDocumentMatrix <- function(txts, pats) {
        # create a dictionary in which the key is the same as the entry
        pats <- quanteda::dictionary(sapply(pats, list))
        # name each "document" which is the text string to be searched
        names(txts) <- txts
        # interpret dictionary entries as regular expressions
        ret <- quanteda::dfm(txts, dictionary = pats, valuetype = "regex", verbose = FALSE)
        # transpose the matrix, coerce to dense logical matrix, remove dimnames
        ret <- t(as.matrix(ret > 0))
        names(dimnames(ret)) <- NULL
        ret
    }
    
    texts <- c('sea','abs','cab')
    patterns <- c('ea','ab','ca')
    
    letterDocumentMatrix(texts, patterns)
    ##      sea   abs   cab
    ## ea  TRUE FALSE FALSE
    ## ab FALSE  TRUE  TRUE
    ## ca FALSE FALSE  TRUE
    

    如果您希望它在大型数据集上快速运行,我建议从函数中删除第三行和倒数第二行。

    【讨论】:

      猜你喜欢
      • 2015-05-19
      • 1970-01-01
      • 2015-05-05
      • 2018-04-29
      • 1970-01-01
      • 2015-08-05
      • 2018-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多