我有一个关于在我的数据集中两个字符串的子字符串之间进行非常快速和高效的比较的问题,尽管机器非常强大,但它运行得不够快.
我有一个data.table
,它有两列和大约15亿行,它的 struct 如下:
library(data.table)
library(stringr)
library(stringi)
library(stringdist)
dt <- data.frame(c("002134", "024345", "176234"), c("002003", "024234", "002004"))
colnames(dt) <- c("class1", "class2")
setDT(dt)
我想要的是一个函数,它(1)为两个向量逐行从每个字符串中提取前3位数字,(2)比较两个向量之间的子字符串,以及(3)创建一个新的布尔变量,报告两个子字符串是否相等.
因此,预期的结果如下:
dt$sameclass <- c(TRUE, TRUE, FALSE)
print(dt)
class1 class2 sameclass
1: 002134 002003 TRUE
2: 024345 024234 TRUE
3: 176234 002004 FALSE
我已经try 了stringr
和stringi
的版本,既有data.table
功能的,也有不具有data.table
功能的.用于比较我使用的子字符串stringdist
,因为据我所知,可以并行化,这在我的服务器上将非常有益.然而,瓶颈似乎仍然是子串提取.
#stringi + stringdist without data.table:
dt$redclass1 <- stri_sub(dt$class1, to = 3)
dt$redclass2 <- stri_sub(dt$class2, to = 3)
dt[, classdist := stringdist(a = redclass1, b = redclass2, method = "hamming")]
dt[, sameclass := (classdist == 0)]
#stringi + stringdist within data.table:
dt[, classdist := stringdist(a = stri_sub(dt$class1, to = 3), b = stri_sub(dt$class2, to = 3), method = "hamming")]
dt[, sameclass := (classdist == 0)]
#stringr with separate function:
sameclass <- function(subclass1, subclass2, classdepth){
truthvalue <- (str_sub(subclass1, end = classdepth) == str_sub(subclass2, end = classdepth))
return(truthvalue)
}
dt[, sameclass := sameclass(subclass1 = class1, subclass2 = class2, classdepth = 3), by = seq_len(nrow(dt))]
所有版本都会遇到内存问题,或者需要几个小时到一天的时间才能运行.因为我需要反复这样做,这对我不起作用,我想问你是否可以想出更快/更有效的方法.如有任何帮助,将不胜感激!
EDIT个
我已经对这里建议的一些方法进行了基准测试,它们确实显示出显著的加速比:
dt <- data.frame(rep(c("002134", "024345", "176234"), 1000), rep(c("002003", "024234", "002004"), 1000))
colnames(dt) <- c("class1", "class2")
setDT(dt)
times <- microbenchmark(
startswithtest = dt[, startsWith(class2, substring(class1, 1, 3))],
lapplytest = dt[, do.call(`==`, lapply(.SD, substring, 1, 3)), .SDcols = c("class1", "class2")],
numerictest = dt[, as.numeric(class1)%/%1000 == as.numeric(class2)%/%1000],
functiontest = dt[, sameclass(subclass1 = class1, subclass2 = class2, classdepth = 3), by = seq_len(nrow(dt))],
stringitest = dt[, stringdist(a = stri_sub(dt$class1, to = 3), b = stri_sub(dt$class2, to = 3), method = "hamming")],
times = 50
)
times
expr min lq mean median uq max neval
startswithtest 312.501 356.901 593.4530 444.8515 737.301 1692.602 50
lapplytest 383.602 439.201 736.3512 522.7010 966.901 2259.601 50
numerictest 1763.100 1932.600 3229.6651 2399.7510 4153.201 8396.301 50
functiontest 45677.700 61124.002 81567.9409 77844.5510 100084.901 133921.502 50
stringitest 794.201 1028.200 1423.5289 1259.6005 1739.400 3640.701 50
我暂时还是使用Start,因为它似乎提供了最高的速度(不幸的是,由于我的服务器的限制,我无法使用C函数).谢谢你的帮助!