R 中字母的术语文档矩阵
Term Document Matrix for Letters in R
我想构建一个 n-gram 'letter document matrix',它基本上使用最多 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
似乎 outer 将整个第一个参数传递给 grepl,而不是一次传递一个条目,导致 grepl 只搜索第一个词,在本例中为 'a'。
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()
来转置它,但在大矩阵上它可能会很慢。
我们可以 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
用于文本分析的 quanteda 包中有一个预建函数可以处理此问题,这需要您将字母序列视为 "dictionary: of regular expressions and building a document-feature matrix where those regular expressions are identified in each " 文档”。作者使用字典整理对 dfm()
函数的调用,您将获得确切的 return 对象。这里我已经按照您的问题转置了它。
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
如果您希望它在大型数据集上快速运行,我建议从函数中删除第三行和倒数第二行。
我想构建一个 n-gram 'letter document matrix',它基本上使用最多 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
似乎 outer 将整个第一个参数传递给 grepl,而不是一次传递一个条目,导致 grepl 只搜索第一个词,在本例中为 'a'。
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()
来转置它,但在大矩阵上它可能会很慢。
我们可以 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
用于文本分析的 quanteda 包中有一个预建函数可以处理此问题,这需要您将字母序列视为 "dictionary: of regular expressions and building a document-feature matrix where those regular expressions are identified in each " 文档”。作者使用字典整理对 dfm()
函数的调用,您将获得确切的 return 对象。这里我已经按照您的问题转置了它。
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
如果您希望它在大型数据集上快速运行,我建议从函数中删除第三行和倒数第二行。