R中字母的术语文档矩阵

时间:2015-10-26 01:48:38

标签: r nlp grepl

我想构建一个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(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'。

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

我们可以在Vectorize

outer获得乐趣
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

答案 2 :(得分:0)

有一个预建的功能可以从 quanteda 包中进行文本分析,这将涉及您将字母序列视为&#34;字典:正则表达式和构建文档 - 在每个&#34;文档&#34;中标识这些正则表达式的特征矩阵。通过使用应用的字典整理对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

如果你想让它在大型数据集上快速工作,我建议从函数中删除第三行和倒数第二行。