Удалить цикл for из алгоритма stringdist в R - PullRequest
1 голос
/ 04 июня 2019

Я создал алгоритм для определения оценок совпадающих строк из 2 кадров данных в R. Он будет искать для каждой строки в test_ech совпадающие строки, у которых их оценка превышает 0,75 в test_data (на основе сопоставления 3 столбцов из каждого фрейм данных).

Ну, мой код отлично работает с маленьким фреймом данных, но я имею дело с фреймами данных длиной 12 м, и этот процесс займет не менее 5 дней. Поэтому я думаю, что если я откажусь от «петель», это сработает, но я действительно не знаю, как это сделать. (и если есть дополнительные изменения, которые мне нужно сделать, чтобы облегчить процесс)

Спасибо.

#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: 65 тыс. Строк и test_data: 12 млн. Строк

#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")))

ожидаемый результат - это фрейм данных с 3 ссылочными столбцами из test_ech с 3 соответствующими столбцами из test_data и оценкой, которая должна быть> 0,75

выходная ссылка

Ответы [ 2 ]

0 голосов
/ 05 июня 2019

Наконец, я решил проблему благодаря @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)

    }
   }
  }
0 голосов
/ 04 июня 2019

Я не уверен, что это полностью решит вашу проблему, учитывая размеры ваших исходных данных, но вы можете существенно сократить время, выполнив один цикл 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. Если вы можете отобразить разницу между stringdist иstringsim, запустив stringdistmatrix и настроив его, вероятно, будет еще быстрее).

...