从 R 中的 stringdist 算法中删除 for 循环
Remove for loop from stringdist algorithm in R
我做了一个算法来确定 R 中 2 个数据帧的匹配字符串的分数。它将搜索 test_ech 中的每一行,它们在 test_data 中的分数高于 0.75 的匹配行(基于每个数据框中 3 列的匹配)。
好吧,我的代码可以完美地处理小型数据框,但我正在处理 1200 万行的数据框,并且该过程至少需要 5 天才能完成。所以我认为如果我丢弃 "for loops" 它会起作用,但我真的不知道该怎么做。 (如果我需要做额外的更改来简化流程)
谢谢。
#score function :
library(stringdist)
score <- function(i,j)
{
s_n<-stringsim(test_ech[j,3],test_data[i,5],method = "jw",p=0.15)
s_v<-stringsim(test_ech[j,5],test_data[i,4],method = "jw",p=0.15)
s_c<-stringsim(test_ech[j,4],test_data[i,3],method = "jw",p=0.15)
return(s_n*0.6+s_v*0.25+s_c*0.15)
}
#initialize result data frame :
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
#algo textmining :
system.time(for (j in 1:nrow(test_ech)) {
for (i in 1:nrow(test_data)) {
x<-score(i,j)
if (x>0.75) {
ligne<-data.frame(nom_AS400=test_ech[j,3],
ville_AS400=test_ech[j,5],
cp_AS400=test_ech[j,4],
nom_SIRENE=test_data[i,5],
ville_SIRENE=test_data[i,4],
cp_SIRENE=test_data[i,3],
score=x)
resultat<-rbind(resultat,ligne)
}
}
})
test_ech:65k 行和test_data:12m 行
#test_ech (5 rows)
structure(list(societe_code = c("01", "01", "01", "01", "01"),
client_code = c("00048I", "00059Z", "00070Q", "00080W", "00131L"
), client_lib = c("CFA VAUBAN", "ALLRIM SA", "ATS CULLIGAN",
"AHSSEA", "ETS BRUNEAU P"), client_cp = c("25001", "25401",
"25480", "70002", "94700"), client_ville = c("BESANCON CEDEX",
"AUDINCOURT CEDEX", "ECOLE VALENTIN", "VESOUL CEDEX", "MAISONS ALFORT"
)))
#test_data (5 rows)
structure(list(siren = c("005450093", "005450095", "005541552",
"005580501", "005620117"), siret = c("00545009300033", "00545009300041",
"00554155200039", "00558050100012", "00562011700019"), codePostalEtablissement = c("04800",
"04802", "04260", "44600", "80100"), libelleCommuneEtablissement = c("GREOUX LES BAINS",
"BAINS", "ALLOS", "SAINT NAZAIRE", "ABBEVILLE"), ref = c("PASSIONNEMENT GLAMOUR",
"GLAMOUR", "LE SYMPA SNACK", "STEF", "DUBOIS")))
预期输出是一个数据框,其中包含来自 test_ech 的 3 个参考列和来自 test_data 的 3 个匹配列,分数应该 >0.75
output link
考虑到原始数据的维度,我不确定这是否能完全解决您的问题,但是您可以通过一个 for
循环而不是两个循环来显着减少时间。您可以这样做,因为 stringsim
函数在一侧接受单个字符对象,在另一侧接受向量。
score_2 <- function(j)
{
s_n <- stringsim(test_ech[[j,3]], test_data[[5]], method = "jw", p = 0.15)
s_v <- stringsim(test_ech[[j,5]], test_data[[4]], method = "jw", p = 0.15)
s_c <- stringsim(test_ech[[j,4]], test_data[[3]], method = "jw", p = 0.15)
return(s_n * 0.6 + s_v * 0.25 + s_c * 0.15)
}
stringsim (test_ech[,3], test_data[,5])
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
for (j in 1:nrow(test_ech)) {
x <- score_2(j)
x_75 = which(x > 0.75)
if(length(x_75) > 0){
for(i in x_75){
ligne<-data.frame(nom_AS400=test_ech[[j,3]],
ville_AS400=test_ech[[j,5]],
cp_AS400=test_ech[[j,4]],
nom_SIRENE=test_data[[i,5]],
ville_SIRENE=test_data[[i,4]],
cp_SIRENE = test_data[[i,3]],
score = x[i])
resultat<-rbind(resultat,ligne)
}
}
}
您的函数,将两个测试对象重复 60 次:
usuário sistema decorrido
9.59 1.43 11.12
这个函数,重复两个测试对象60次:
usuário sistema decorrido
0.21 0.08 0.18
快了一点:)
(注意:有 stringdistmatrix
接受两边的向量和 returns 矩阵,但遗憾的是没有 stringsimmatrix
。如果你能找出 stringsimmatrix
之间的区别=17=] 和 stringsim
, 运行 stringdistmatrix
并调整它可能会更快)。
最后,感谢@Luis,我只使用一个循环而不是两个循环解决了这个问题。
代码如下:
score_2 <- function(j)
{
s_n <- stringsim(test_ech[[j,3]], test_data[[5]], method = "jw", p = 0.15)
s_v <- stringsim(test_ech[[j,5]], test_data[[4]], method = "jw", p = 0.15)
s_c <- stringsim(test_ech[[j,4]], test_data[[3]], method = "jw", p = 0.15)
return(s_n * 0.6 + s_v * 0.25 + s_c * 0.15)
}
stringsim (test_ech[,3], test_data[,5])
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
for (j in 1:nrow(test_ech)) {
x <- score_2(j)
x_75 = which(x > 0.75)
if(length(x_75) > 0){
for(i in x_75){
ligne<-data.frame(nom_AS400=test_ech[[j,3]],
ville_AS400=test_ech[[j,5]],
cp_AS400=test_ech[[j,4]],
nom_SIRENE=test_data[[i,5]],
ville_SIRENE=test_data[[i,4]],
cp_SIRENE = test_data[[i,3]],
score = x[i])
resultat<-rbind(resultat,ligne)
}
}
}
我做了一个算法来确定 R 中 2 个数据帧的匹配字符串的分数。它将搜索 test_ech 中的每一行,它们在 test_data 中的分数高于 0.75 的匹配行(基于每个数据框中 3 列的匹配)。
好吧,我的代码可以完美地处理小型数据框,但我正在处理 1200 万行的数据框,并且该过程至少需要 5 天才能完成。所以我认为如果我丢弃 "for loops" 它会起作用,但我真的不知道该怎么做。 (如果我需要做额外的更改来简化流程)
谢谢。
#score function :
library(stringdist)
score <- function(i,j)
{
s_n<-stringsim(test_ech[j,3],test_data[i,5],method = "jw",p=0.15)
s_v<-stringsim(test_ech[j,5],test_data[i,4],method = "jw",p=0.15)
s_c<-stringsim(test_ech[j,4],test_data[i,3],method = "jw",p=0.15)
return(s_n*0.6+s_v*0.25+s_c*0.15)
}
#initialize result data frame :
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
#algo textmining :
system.time(for (j in 1:nrow(test_ech)) {
for (i in 1:nrow(test_data)) {
x<-score(i,j)
if (x>0.75) {
ligne<-data.frame(nom_AS400=test_ech[j,3],
ville_AS400=test_ech[j,5],
cp_AS400=test_ech[j,4],
nom_SIRENE=test_data[i,5],
ville_SIRENE=test_data[i,4],
cp_SIRENE=test_data[i,3],
score=x)
resultat<-rbind(resultat,ligne)
}
}
})
test_ech:65k 行和test_data:12m 行
#test_ech (5 rows)
structure(list(societe_code = c("01", "01", "01", "01", "01"),
client_code = c("00048I", "00059Z", "00070Q", "00080W", "00131L"
), client_lib = c("CFA VAUBAN", "ALLRIM SA", "ATS CULLIGAN",
"AHSSEA", "ETS BRUNEAU P"), client_cp = c("25001", "25401",
"25480", "70002", "94700"), client_ville = c("BESANCON CEDEX",
"AUDINCOURT CEDEX", "ECOLE VALENTIN", "VESOUL CEDEX", "MAISONS ALFORT"
)))
#test_data (5 rows)
structure(list(siren = c("005450093", "005450095", "005541552",
"005580501", "005620117"), siret = c("00545009300033", "00545009300041",
"00554155200039", "00558050100012", "00562011700019"), codePostalEtablissement = c("04800",
"04802", "04260", "44600", "80100"), libelleCommuneEtablissement = c("GREOUX LES BAINS",
"BAINS", "ALLOS", "SAINT NAZAIRE", "ABBEVILLE"), ref = c("PASSIONNEMENT GLAMOUR",
"GLAMOUR", "LE SYMPA SNACK", "STEF", "DUBOIS")))
预期输出是一个数据框,其中包含来自 test_ech 的 3 个参考列和来自 test_data 的 3 个匹配列,分数应该 >0.75
output link
考虑到原始数据的维度,我不确定这是否能完全解决您的问题,但是您可以通过一个 for
循环而不是两个循环来显着减少时间。您可以这样做,因为 stringsim
函数在一侧接受单个字符对象,在另一侧接受向量。
score_2 <- function(j)
{
s_n <- stringsim(test_ech[[j,3]], test_data[[5]], method = "jw", p = 0.15)
s_v <- stringsim(test_ech[[j,5]], test_data[[4]], method = "jw", p = 0.15)
s_c <- stringsim(test_ech[[j,4]], test_data[[3]], method = "jw", p = 0.15)
return(s_n * 0.6 + s_v * 0.25 + s_c * 0.15)
}
stringsim (test_ech[,3], test_data[,5])
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
for (j in 1:nrow(test_ech)) {
x <- score_2(j)
x_75 = which(x > 0.75)
if(length(x_75) > 0){
for(i in x_75){
ligne<-data.frame(nom_AS400=test_ech[[j,3]],
ville_AS400=test_ech[[j,5]],
cp_AS400=test_ech[[j,4]],
nom_SIRENE=test_data[[i,5]],
ville_SIRENE=test_data[[i,4]],
cp_SIRENE = test_data[[i,3]],
score = x[i])
resultat<-rbind(resultat,ligne)
}
}
}
您的函数,将两个测试对象重复 60 次:
usuário sistema decorrido
9.59 1.43 11.12
这个函数,重复两个测试对象60次:
usuário sistema decorrido
0.21 0.08 0.18
快了一点:)
(注意:有 stringdistmatrix
接受两边的向量和 returns 矩阵,但遗憾的是没有 stringsimmatrix
。如果你能找出 stringsimmatrix
之间的区别=17=] 和 stringsim
, 运行 stringdistmatrix
并调整它可能会更快)。
最后,感谢@Luis,我只使用一个循环而不是两个循环解决了这个问题。
代码如下:
score_2 <- function(j)
{
s_n <- stringsim(test_ech[[j,3]], test_data[[5]], method = "jw", p = 0.15)
s_v <- stringsim(test_ech[[j,5]], test_data[[4]], method = "jw", p = 0.15)
s_c <- stringsim(test_ech[[j,4]], test_data[[3]], method = "jw", p = 0.15)
return(s_n * 0.6 + s_v * 0.25 + s_c * 0.15)
}
stringsim (test_ech[,3], test_data[,5])
resultat<-data.frame(nom_AS400=character(),ville_AS400=character(),cp_AS400=character(), nom_SIRENE=character(),ville_SIRENE=character(),cp_SIRENE=character(),score=double())
for (j in 1:nrow(test_ech)) {
x <- score_2(j)
x_75 = which(x > 0.75)
if(length(x_75) > 0){
for(i in x_75){
ligne<-data.frame(nom_AS400=test_ech[[j,3]],
ville_AS400=test_ech[[j,5]],
cp_AS400=test_ech[[j,4]],
nom_SIRENE=test_data[[i,5]],
ville_SIRENE=test_data[[i,4]],
cp_SIRENE = test_data[[i,3]],
score = x[i])
resultat<-rbind(resultat,ligne)
}
}
}