Comparação de valor linha a linha entre dois dataframes e en

Boa noite pessoal! Estou precisando de uma ajuda em algo simples, mas não estou conseguindo resolver.
Eu tenho dois dataframes, df1 e df2.
No df1, tenho uma coluna de ceps de 8 dígitos.
No df2, tenho uma coluna com cidade, outra com estado, outra com o cep de início da faixa de ceps da cidade e a última coluna com o cep do fim da faixa.
Preciso verificar cada cep do df1, em qual faixa de ceps do df2 se encaixa e copiar a cidade é o estado do df2 para o df1.
O objetivo aqui é preencher o df1 com mais duas colunas de cidade e estado.
Como o df1 tem mais de 600 mil linhas e o df2 mais de 11 milhões de linhas, preciso fazer de uma forma vetorizavel.
Já tentei usar loop For mas demora demais e não termina. Já tentei utilizar mutate( ifelse()) mas ultrapassa a memória.
Alguém de vocês poderia me ajudar, por favor?
Muito obrigado!!!

Eu nao testei as velocidades, mas acho que as três maneiras abaixo, alguma deve dar legal! Veja se resolve.

  library(tidyverse)
  
  # gera dados de brinquedo ------------------------
  df1 <- data.frame(
      cep = c("11001-000", "06001-000")
  )
  
  df2 <- data.frame(
      cidade = c("sao paulo", "osasco"),
      estado = c("sp", "sp"),
      cep_ini = c(11000, 6000),
      cep_fim = c(11999, 6299)
  )
  
  # dataprep ----------------------------------------
  # extrai os primeiros 5 digitos do cep
  df1 <- df1 %>%
      mutate(
          primeiros_5_digitos_do_cep = as.numeric(substr(cep, 1, 5))
      )
  
  # usando fuzzyjoin + tidyverse --------------------
  library(fuzzyjoin)
  df1 %>%
      fuzzy_left_join(
          df2,
          by = c("primeiros_5_digitos_do_cep" = "cep_ini", "primeiros_5_digitos_do_cep" = "cep_fim"),
          match_fun = list(`>=`, `<=`)
      ) %>%
      select(-primeiros_5_digitos_do_cep, -cep_ini, -cep_fim)
#>         cep    cidade estado
#> 1 11001-000 sao paulo     sp
#> 2 06001-000    osasco     sp
  
  
  
  # usando sqldf --------------------
  library(sqldf)
  
  sqldf("
      SELECT cep, cidade, estado
      FROM df1
      LEFT JOIN df2 ON primeiros_5_digitos_do_cep BETWEEN cep_ini and cep_fim
")
#>         cep    cidade estado
#> 1 11001-000 sao paulo     sp
#> 2 06001-000    osasco     sp
  
  # usando data.table ---------------
  library(data.table)
  
  df1dt <- as.data.table(df1)
  df2dt <- as.data.table(df2)
  setkey(df2dt, cep_ini, cep_fim)
  
  foverlaps(
      df1dt %>% mutate(primeiros_5_digitos_do_cep2 = primeiros_5_digitos_do_cep), 
      df2dt, 
      by.x = c("primeiros_5_digitos_do_cep", "primeiros_5_digitos_do_cep2"),
      by.y = c("cep_ini", "cep_fim")
  ) %>%
      select(-primeiros_5_digitos_do_cep, -cep_ini, -cep_fim)
#>       cidade estado       cep primeiros_5_digitos_do_cep2
#> 1: sao paulo     sp 11001-000                       11001
#> 2:    osasco     sp 06001-000                        6001

Created on 2020-12-10 by the reprex package (v0.3.0)

eu usei esse post como referência:

Olá Athos, bom dia!!!

Muito obrigado pela sua resposta!!! Inicialmente eu tentei utilizar a solução número 1 que você enviou e apesar de ela parecer bem interessante, para mim começou a apresentar erro de vetor e etc… Como eu estava com pouco tempo para debugar, construí baseado na sua solução 2 com o sqldf e funcionou perfeitamente. Demorou 3 horas pra rodar no meu Mac, mas, resolveu o problema e integrou os 2 dataframes perfeitamente!!!
Muito obrigado novamente e um grande abraço!!

Antonio.

1 curtida