我有一个关于在我的数据集中两个字符串的子字符串之间进行非常快速和高效的比较的问题,尽管机器非常强大,但它运行得不够快. 我有一个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 了stringrstringi的版本,既有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函数).谢谢你的帮助!

推荐答案

也许你可以试一试

> dt[, sameclass := do.call(`==`, lapply(.SD, substring, 1, 3))][]
   class1 class2 sameclass
1: 002134 002003      TRUE
2: 024345 024234      TRUE
3: 176234 002004     FALSE

或者可能更快

> dt[, sameclass := startsWith(class2, substring(class1, 1, 3))][]
   class1 class2 sameclass
1: 002134 002003      TRUE
2: 024345 024234      TRUE
3: 176234 002004     FALSE

R相关问答推荐

如何删除字符串中重复的字符序列?

如何提高以键ID为列的表中键查找的效率?

如何创建具有总计列和ggplot 2所有条线的百分比标签的堆叠条形图?

DT::可数据的正规表达OR运算符问题

在特定列上滞后n行,同时扩展框架的长度

R形式的一维数字线/箱形图样式图表

具有多个依赖变量/LHS的逻辑模型

如何根据条件计算时差(天)

在垂直轴中包含多个ggplot2图中的平均值

ggplot2中的X轴显示数值,单位为百,而不是十

如何使下一个按钮只出现在Rshiny 的一段时间后?""

使用rest从header(h2,h3,table)提取分层信息

根据类别合并(汇总)某些行

用R ggplot2求上、下三角形中两个变量的矩阵热图

在GG图中绘制射线的自动程序

查找所有站点的最小值

使用R将简单的JSON解析为嵌套框架

为什么在写入CSV文件时Purrr::Pwalk不起作用

有没有办法通过str_Detect()或其他字符串匹配函数来连接两个长度不等的数据帧?

ggplot斜体轴刻度标签中的单个字符-以前的帖子建议不工作