Pow*_*ege 9 sorting string performance r
如何有效地对向量中每个字符串的字符进行排序?例如,给定一个字符串向量:
set.seed(1)
strings <- c(do.call(paste0, replicate(4, sample(LETTERS, 10000, TRUE), FALSE)),
do.call(paste0, replicate(3, sample(LETTERS, 10000, TRUE), FALSE)),
do.call(paste0, replicate(2, sample(LETTERS, 10000, TRUE), FALSE)))
Run Code Online (Sandbox Code Playgroud)
我编写了一个函数,该函数将每个字符串分成一个向量,对向量进行排序,然后折叠输出:
sort_cat <- function(strings){
tmp <- strsplit(strings, split="")
tmp <- lapply(tmp, sort)
tmp <- lapply(tmp, paste0, collapse = "")
tmp <- unlist(tmp)
return(tmp)
}
sorted_strings <- sort_cat(strings)
Run Code Online (Sandbox Code Playgroud)
但是,我需要将其应用到的字符串向量很长,并且此功能太慢。有没有人对如何提高性能有任何建议?
您可以通过最小化循环次数来减少时间,并通过使用parallel包进一步做到这一点...我的方法是分割字符串一次,然后在循环中排序并粘贴:
sort_cat <- function(strings){
tmp <- strsplit(strings, split="")
tmp <- lapply(tmp, sort)
tmp <- lapply(tmp, paste0, collapse = "")
tmp <- unlist(tmp)
return(tmp)
}
sort_cat2 <- function(strings){
unlist(mcMap(function(i){
stri_join(sort(i), collapse = "")
}, stri_split_regex(strings, "|", omit_empty = TRUE, simplify = F), mc.cores = 8L))
}
> microbenchmark::microbenchmark(
+ old = sort_cat(strings[1:500000]),
+ new = sort_cat2(strings[1:500000]),
+ times = 1
+ )
Unit: seconds
expr min lq mean median uq max neval
old 9.62673395 9.62673395 9.62673395 9.62673395 9.62673395 9.62673395 1
new 5.10547437 5.10547437 5.10547437 5.10547437 5.10547437 5.10547437 1
Run Code Online (Sandbox Code Playgroud)
剃须大概4秒,但还是没那么快......
好吧,apply在这里使用..策略:
1) 提取字母而不是分割边界 2) 使用结果创建一个矩阵 3) 逐行迭代 4) 排序 5) 连接
您可以避免多个循环和取消列出......忽略:?警告是如果字符串长度不同,您需要删除诸如中的任何空或applyNAi[!is.na(i) && nchar(i) > 0]
sort_cat3 <- function(strings){
apply(stri_extract_all_regex(strings, "\\p{L}", simplify = TRUE), 1, function(i){
stri_join(stri_sort(i), collapse = "")
})
}
> microbenchmark::microbenchmark(
+ old = sort_cat(strings[1:500000]),
+ mapping = sort_cat2(strings[1:500000]),
+ applying = sort_cat3(strings[1:500000]),
+ times = 1
+ )
Unit: seconds
expr min lq mean median uq max neval
old 10.35101934 10.35101934 10.35101934 10.35101934 10.35101934 10.35101934 1
mapping 5.12771799 5.12771799 5.12771799 5.12771799 5.12771799 5.12771799 1
applying 3.97775326 3.97775326 3.97775326 3.97775326 3.97775326 3.97775326 1
Run Code Online (Sandbox Code Playgroud)
将我们从 10.3 秒缩短到 3.98 秒