1

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

4

3 回答 3

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()来转置它,但在大型矩阵上可能会很慢。

于 2015-10-26T02:01:38.023 回答
1

我们可以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
于 2015-10-26T02:12:09.360 回答
0

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-10-26T07:22:02.233 回答