【问题标题】:Remove for loop from stringdist algorithm in R从 R 中的 stringdist 算法中删除 for 循环
【发布时间】:2019-06-04 12:31:30
【问题描述】:

我已经制定了一个算法来确定 R 中 2 个数据帧中匹配字符串的分数。它将在 test_ech 中搜索每一行在 test_data 中其分数高于 0.75 的匹配行(基于每个 3 列的匹配数据框)。

好吧,我的代码可以完美地处理小数据框,但我正在处理 12m 行的数据框,这个过程至少需要 5 天才能完成。所以我认为如果我丢弃“for循环”它会起作用,但我真的不知道该怎么做。 (如果我需要做一些额外的改变来减轻这个过程)

谢谢。

#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

【问题讨论】:

  • 嗨,Amine,你能给我们一个使用 dput() 函数的数据库样本吗?
  • 恐怕你得调用score 12m·12m 次,也就是1,4·10^14,很多。无论您使用的是 for 循环还是数组……
  • 你可以并行运行它,用漂亮的电脑看看未来的包
  • @ziggystar 我在最后更新了帖子...test_ech:65k 行和 test_data:12m 行...所以是的,您必须为总共 65k 行调用 score 12m 次
  • @Luis 我更新了帖子,您可以使用 dput() 函数找到 2 个数据框

标签: r for-loop stringdist


【解决方案1】:

鉴于原始数据的维度,我不确定这是否能完全解决您的问题,但您可以通过一个 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,它接受两边的向量并返回一个矩阵,但遗憾的是没有stringsimmatrix。如果你能找出stringdiststringsim之间的区别,运行@987654330 @ 并且调整它可能会更快)。

【讨论】:

  • 感谢您的回复,我喜欢只使用一个循环而不是两个循环。然而, score 函数有一个问题,它会计算 test_ech[,3] 中的一个字符串与包含 test_data[,5] 中所有字符串的向量的分数匹配,最后它会返回匹配 test_data 中的所有字符串时的分数,而不是每个匹配的每个分数。
  • 我已在回复帖子中更新了您的代码...非常感谢您的帮助
  • @Amine96 啊,你是对的,应该是 x[i] 而不是 x[x_75]。不管怎样,至少你的问题解决了。你介意接受我的回答吗?
  • 不用担心,但您需要用我的代码更新您的代码以将其标记为答案。(我还在 test_data 和 test_ech 中使用 [[]] 更改了 score 函数)
【解决方案2】:

最后,感谢@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)

    }
   }
  }

【讨论】:

    猜你喜欢
    • 2015-09-25
    • 2017-08-13
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 2021-07-04
    • 2015-02-20
    • 2017-08-20
    相关资源
    最近更新 更多