案例研究:在R中加速Mapply
我必须做一个程序,找出“相似”的句子。 在这种情况下,句子只是整数向量。(我们可以假设我们已经将字符串和单词句子预处理为整数向量)。为了简单起见,我们所有的句子都有相同的长度,如果两个句子只有一个单词被另一个单词所代替,那么它们是相似的 例如,(4,3,1,2)和(4,2,1,2)是相似的,因为它们的区别只是第二个数字3被2代替 句子存储在data.table案例研究:在R中加速Mapply,r,performance,mapply,R,Performance,Mapply,我必须做一个程序,找出“相似”的句子。 在这种情况下,句子只是整数向量。(我们可以假设我们已经将字符串和单词句子预处理为整数向量)。为了简单起见,我们所有的句子都有相同的长度,如果两个句子只有一个单词被另一个单词所代替,那么它们是相似的 例如,(4,3,1,2)和(4,2,1,2)是相似的,因为它们的区别只是第二个数字3被2代替 句子存储在data.tableDT中。有两列,一列是ID,另一列是char向量 我们在ID\u pair中得到了一个对ID列表,我们需要检查DT中的相应句子是否相似 下
DT
中。有两列,一列是ID,另一列是char向量
我们在ID\u pair
中得到了一个对ID列表,我们需要检查DT
中的相应句子是否相似
下面是一个代码示例。
现在,我对mapply
的实现不满意,因为我发现它太慢了。(10秒仅用于100000对检查!!)
我相信这样做会更有效率。[我需要这样做,因为我必须为该项目扫描数千万或数亿张支票!]
注:
(1) 我试图实现一个哈希表。奇怪的是,它并没有让事情变得更快。
(2) 也许这是因为DT
的第V列是一个列表,这会导致问题吗?我还有什么选择?
(3) 如果有一个解决方案可以加快速度,我需要在第二部分中寻找另一个相似性的概念,其中两个句子不同,只需添加(任何地方)一个单词。这就是为什么我在本例中选择了一个列表来存储数据,以便能够将不同长度的句子放在同一列中。
也许这是错的
谢谢
library(hash)
library(data.table)
is_pair_sub <- function(ID1,ID2){
sum(!DT$V[[which(DT$ID==ID1)]]==DT$V[[which(DT$ID==ID2)]])==1
# sum(!values(s_hash,ID1)[,1]==values(s_hash,ID2)[,1])==1
}
set.seed(123)
N <- 2000
k <- 4 #size of alphabet
V <- lapply(1:N,function(x){sample(1:k,4,replace=TRUE)})
DT <- data.table(ID=sample(1:N),V)
N_pair_sub <- 100000
ID_pair <- data.table(matrix(sample(1:N,2*N_pair_sub,replace=TRUE),nrow=N_pair_sub,ncol=2))
s_hash <- hash(DT$ID,DT$V)
print(system.time({
x <- mapply(is_pair_sub,ID_pair$V1,ID_pair$V2) }))
ID_pair[x]
库(散列)
库(数据表)
is\u pair\u sub这不是很可靠,但是adist
对于这个特定的示例很有效。分析您的代码,您将看到大部分时间实际上都花在了is\u sub
函数上。如果您不能使用其中一个可用的距离函数(从base R或一些用C编写的包中),您必须用C编写自己的距离函数(例如,使用Rcpp)。当然,C更快。但是在R中,有什么改进是可能的?现有的距离函数是用C实现的,这是一个原因。纯R无法获得足够的性能。@Roland在本例中,我应该自己编写函数,因为我没有发现任何R包提供我需要的正确函数。。。但要获得更高的性能,最好的方法是。。。简单地说,不要用R来解决这类问题!至少看起来是这样!
is_pair_edit1 <- function(ID1, ID2) { #ID1 and #ID2 should be 1 length apart}
split1=values(s_hash,ID1)[,1]
split2=values(s_hash,ID2)[,1]
l2=length(split2)
l1=l2-1 #this is by construction
# if (! (len1==len2)){return(FALSE) }
# this has been already tested
index = 1
diff = 0
if (l1==l2) {return(FALSE)}
if (l1>l2) {
while ( index < l1) {
if( diff==0) {
if (split1[index] != split2[index]) {diff=1}
else {index <- index + 1}
}
else { #diff==1
if (split1[index+1]!=split2[index]) {return(FALSE)}
else {index <- index + 1}
}
} #end of while
return (TRUE) #should be TRUE anyway if we get there
} #end of if
else {
while ( index < l2) {
if( diff==0) {
if (split1[index] != split2[index]) {diff=1}
else {index <- index + 1}
}
else { #diff==1
if (split2[index+1]!=split1[index]) {return(FALSE)}
else {index <- index + 1}
}
} #end of while
return (TRUE) #should be TRUE anyway if we get there
} #end of else #(l2>l1)
} #end of function is_pair_edit1
V <- lapply(1:N,function(x){sample(1:k,5,replace=TRUE)})
DT1= data.table(ID=sample((N+1):(2*N)),V)
DT = rbindlist(list(DT,DT1))
ID_pair1 <- ID_pair
ID_pair1$V2 <- ID_pair1$V2+N #to generate IDs referencing sentences of length 5.
s_hash <- hash(DT$ID,DT$V)
print(system.time({
y <- mapply(is_pair_edit1,ID_pair1$V1,ID_pair1$V2) }))
print(DT[ID==ID_pair1[y][1,]$V1])
print(DT[ID==ID_pair1[y][1,]$V2])