Передача аргументов в несколько функций match_fun в R fuzzyjoin :: fuzzy_join

Я отвечал на эти два вопроса и получил адекватное решение, но у меня возникли проблемы с передачей аргументов с использованием fuzzy_join в match_fun, который я извлек из fuzzyjoin::stringdist_join. В этом случае я использую сочетание нескольких match_fun, включая этот настроенный match_fun_stringdist, а также == и <= для точного соответствия и соответствия критериям.

Я получаю следующее сообщение об ошибке:

# Error in mf(rep(u_x, n_y), rep(u_y, each = n_x), ...): object 'ignore_case' not found


# Data:
library(data.table, quietly = TRUE)
Address1 <- c("786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr","23/4, 23RD FLOOR, STREET 2, ABC-E, PQR","45-B, GALI NO5, XYZ","HECTIC, 99 STREET, PQR")
AREACODE <- c('10','10','14','20','30')
Year1 <- c(2001:2005)

Address2 <- c("abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR","abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR")
Year2 <- c(2001:2010)
AREA_CODE <- c('10','10','10','20','30','40','50','61','64', '99')

data1 <- data.table(Address1, Year1, AREACODE)
data2 <- data.table(Address2, Year2, AREA_CODE)
data2[, unique_id := sprintf("%06d", 1:nrow(data2))]

# Solution:
library(fuzzyjoin, quietly = TRUE); library(dplyr, quietly = TRUE)

# First, need to define match_fun_stringdist 
# Code from stringdist_join from https://github.com/dgrtwo/fuzzyjoin/blob/master/R/stringdist_join.R
match_fun_stringdist <- function(v1, v2, ...) {

  if (ignore_case) {
    v1 <- stringr::str_to_lower(v1)
    v2 <- stringr::str_to_lower(v2)
  }

  dists <- stringdist::stringdist(v1, v2, method = method, ...)

  ret <- dplyr::data_frame(include = (dists <= max_dist))
  if (!is.null(distance_col)) {
    ret[[distance_col]] <- dists
  }
  ret
}

# Call fuzzy_join
fuzzy_join(data1, data2, 
           by = list(x = c("Address1", "AREACODE", "Year1"), y = c("Address2", "AREA_CODE", "Year2")), 
           match_fun = list(match_fun_stringdist, `==`, `<=`),
           mode = "left",
           ignore_case = FALSE,
           method = "dl",
           max_dist = 99,
           distance_col = "dist"
) %>%
  group_by(Address1, Year1, AREACODE) %>%
  top_n(1, -Address1.dist) %>%
  top_n(1, Year2) %>%
  select(unique_id, Address1.dist, everything())
#> Error in mf(rep(u_x, n_y), rep(u_y, each = n_x), ...): object 'ignore_case' not found

person Arthur Yip    schedule 06.06.2017    source источник


Ответы (1)


Я думаю, что ошибка связана с тем, что аргументы, переданные в каждый из нескольких match_fun, испортили его, т.е. не могут передать дополнительные аргументы, такие как ignore_case, изначально предназначенные только для string_dist match_fun, в match_fun >=

Решением было бы определить мой собственный match_fun с фиксированными параметрами для аргументов. См. Ниже, где я определяю свой собственный match_fun_stringdist с фиксированными параметрами. Я также реализовал это здесь в другом вопросе / ответе https://stackoverflow.com/a/44383103/4663008.

# First, need to define match_fun_stringdist 
# Code from stringdist_join from https://github.com/dgrtwo/fuzzyjoin
match_fun_stringdist <- function(v1, v2) {

  # Can't pass these parameters in from fuzzy_join because of multiple incompatible match_funs, so I set them here.
  ignore_case = FALSE
  method = "dl"
  max_dist = 99
  distance_col = "dist"

  if (ignore_case) {
    v1 <- stringr::str_to_lower(v1)
    v2 <- stringr::str_to_lower(v2)
  }

  # shortcut for Levenshtein-like methods: if the difference in
  # string length is greater than the maximum string distance, the
  # edit distance must be at least that large

  # length is much faster to compute than string distance
  if (method %in% c("osa", "lv", "dl")) {
    length_diff <- abs(stringr::str_length(v1) - stringr::str_length(v2))
    include <- length_diff <= max_dist

    dists <- rep(NA, length(v1))

    dists[include] <- stringdist::stringdist(v1[include], v2[include], method = method)
  } else {
    # have to compute them all
    dists <- stringdist::stringdist(v1, v2, method = method)
  }
  ret <- dplyr::data_frame(include = (dists <= max_dist))
  if (!is.null(distance_col)) {
    ret[[distance_col]] <- dists
  }
  ret
}

и вызовите fuzzy_join

fuzzy_join(data1, data2, 
           by = list(x = c("Address1", "AREACODE", "Year1"), y = c("Address2", "AREA_CODE", "Year2")), 
           match_fun = list(match_fun_stringdist, `==`, `<=`),
           mode = "left")
person Arthur Yip    schedule 02.07.2017
comment
Я получаю ту же ошибку. Эта проблема зарегистрирована здесь: github.com/dgrtwo/fuzzyjoin/issues/50 - person Michael Szczepaniak; 11.12.2018
comment
Оказывается, у меня все заработало нормально, когда я использовал обратные тики вместо одинарных кавычек. Я добавил дополнительные комментарии в ветку github, в которых показан код моего примера. - person Michael Szczepaniak; 12.12.2018
comment
Хорошо, я использовал обратные кавычки; однако в моем случае я пытался предоставить сложный список match_funs (match_fun = list (match_fun_stringdist, ==, <=) - person Arthur Yip; 18.03.2019
comment
Как вы смогли заставить это работать без определения max_dist в match_fun_stringdist? Я получаю сообщение об ошибке Error in eval_tidy(xs[[i]], unique_output) : object 'max_dist' not found, хотя я определил ее так же, как вы в вызове нечеткого соединения. - person epi_n00b; 15.05.2019
comment
Извините, у меня здесь устаревший ответ. Теперь исправлено. - person Arthur Yip; 16.05.2019
comment
Я пытаюсь сделать что-то подобное, я думаю, что фабрики функций могут быть хорошим способом, поэтому вам не нужно писать кучу похожих пользовательских функций. adv-r.hadley.nz/function-factories.html - person Oliver; 27.09.2019