Ограничение количества сравнений нечетких строк путем сравнения по подгруппе

У меня есть два следующих набора данных:

DT1 <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 
2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 
2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 
2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 
2001, 2002, 2002, 2002), Municipality = c("Something", "Anything", 
"Nothing", "Something", "Anything", "Nothing", "Something", "Anything", 
"Nothing", "Something", "Anything", "Nothing", "Something", "Anything", 
"Nothing", "Something", "Anything", "Nothing", "Something", "Anything", 
"Nothing", "Something", "Anything", "Nothing", "Something", "Anything", 
"Nothing"), Values = c(0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 
0.85, 0.99, 0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 0.85, 0.99, 
0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 0.85, 0.99)), row.names = c(NA, 
-27L), class = c("tbl_df", "tbl", "data.frame"))

DT2 <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 
2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 
2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 
2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 
2001, 2002, 2002, 2002), Municipality = c("Some", "Anything", 
"Nothing", "Someth.", "Anything", "Not", "Something", "Anything", 
"None", "Some", "Anything", "Nothing", "Someth.", "Anything", 
"Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", 
"Someth.", "Anything", "Not", "Something", "Anything", "None"
), `Other Values` = c(0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 
0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 
0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 
0.8, 0.14, 0.15, 0.01)), row.names = c(NA, -27L), class = c("tbl_df", 
"tbl", "data.frame"))

Я пытаюсь сопоставить их следующим образом, предложенным в этом ссылка, автор Артур Йип.

library(fuzzyjoin); library(dplyr);
stringdist_join(DT1, DT2, 
                by = "Municipality",
                mode = "left",
                ignore_case = TRUE, 
                method = "jw", 
                max_dist = 10, 
                distance_col = "dist") %>%
  group_by(Municipality.x) %>%
  top_n(1, -dist)

Проблема в том, что код полностью «поджаривает» мой компьютер, поэтому я хотел бы разбить код на группы, чтобы ограничить количество сравнений строк. Я пытался:

library(fuzzyjoin); library(dplyr);
stringdist_join(DT1, DT2, 
                by = c("Municipality","Year", "State"),
                mode = "left",
                ignore_case = TRUE, 
                method = "jw", 
                max_dist = 10, 
                distance_col = "dist") %>%
  group_by(Municipality.x) %>%
  top_n(1, -dist)

stringdist_join(DT1, DT2, 
                by = "Municipality",
                mode = "left",
                ignore_case = TRUE, 
                method = "jw", 
                max_dist = 10, 
                distance_col = "dist") %>%
  group_by(Municipality, Year, Province) %>%
  top_n(1, -dist)

Но оба дают мне следующие соответствующие ошибки:

Error: All columns in a tibble must be vectors.
x Column `col` is NULL.
Run `rlang::last_error()` to see where the error occurred.

А также:

Error: Must group by variables found in `.data`.
* Column `Municipality` is not found.
* Column `Year` is not found.
* Column `Province` is not found.
Run `rlang::last_error()` to see where the error occurred.

Как правильно это сделать?


person Tom    schedule 07.12.2020    source источник


Ответы (1)


Вы были на правильном пути - всего несколько опечаток / ошибок, и вам нужно закончить изменение / замену имен столбцов.

Кроме того, в первом вам нужно будет выяснить, как вы хотите выбрать наилучшее совпадение на основе Municipality.dist, Province.dist и Year.dist.

Возможно, второй вариант сработает лучше, если сначала разобраться с годами и провинциями.


DT1 <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002), Municipality = c("Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing", "Something", "Anything", "Nothing"), Values = c(0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 0.85, 0.99, 0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 0.85, 0.99, 0.59, 0.58, 0.66, 0.53, 0.94, 0.2, 0.86, 0.85, 0.99)), row.names = c(NA, -27L), class = c("tbl_df", "tbl", "data.frame"))

DT2 <- structure(list(Province = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3), Year = c(2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002, 2000, 2000, 2000, 2001, 2001, 2001, 2002, 2002, 2002), Municipality = c("Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None", "Some", "Anything", "Nothing", "Someth.", "Anything", "Not", "Something", "Anything", "None"), `Other Values` = c(0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01, 0.41, 0.42, 0.34, 0.47, 0.0600000000000001, 0.8, 0.14, 0.15, 0.01)), row.names = c(NA, -27L), class = c("tbl_df", "tbl", "data.frame"))

library(fuzzyjoin); library(dplyr);

stringdist_join(DT1, DT2, 
                by = c("Municipality", "Year", "Province"),
                mode = "left",
                ignore_case = TRUE, 
                method = "jw", 
                max_dist = 10, 
                distance_col = "dist") %>%
    group_by(Municipality.x) %>%
    slice_min(Municipality.dist)
#> # A tibble: 135 x 12
#> # Groups:   Municipality.x [3]
#>    Province.x Year.x Municipality.x Values Province.y Year.y Municipality.y
#>         <dbl>  <dbl> <chr>           <dbl>      <dbl>  <dbl> <chr>         
#>  1          1   2000 Anything        0.580          1   2000 Anything      
#>  2          1   2000 Anything        0.580          1   2001 Anything      
#>  3          1   2000 Anything        0.580          1   2002 Anything      
#>  4          1   2000 Anything        0.580          2   2000 Anything      
#>  5          1   2000 Anything        0.580          2   2001 Anything      
#>  6          1   2000 Anything        0.580          2   2002 Anything      
#>  7          1   2000 Anything        0.580          3   2000 Anything      
#>  8          1   2000 Anything        0.580          3   2001 Anything      
#>  9          1   2000 Anything        0.580          3   2002 Anything      
#> 10          1   2001 Anything        0.94           1   2000 Anything      
#> # ... with 125 more rows, and 5 more variables: `Other Values` <dbl>,
#> #   Municipality.dist <dbl>, Province.dist <dbl>, Year.dist <dbl>, dist <lgl>

stringdist_join(DT1, DT2, 
                by = "Municipality",
                mode = "left",
                ignore_case = TRUE, 
                method = "jw", 
                max_dist = 10, 
                distance_col = "dist") %>%
    group_by(Municipality.x, Year.x, Province.x) %>%
    slice_min(dist)
#> # A tibble: 135 x 9
#> # Groups:   Municipality.x, Year.x, Province.x [27]
#>    Province.x Year.x Municipality.x Values Province.y Year.y Municipality.y
#>         <dbl>  <dbl> <chr>           <dbl>      <dbl>  <dbl> <chr>         
#>  1          1   2000 Anything        0.580          1   2000 Anything      
#>  2          1   2000 Anything        0.580          1   2001 Anything      
#>  3          1   2000 Anything        0.580          1   2002 Anything      
#>  4          1   2000 Anything        0.580          2   2000 Anything      
#>  5          1   2000 Anything        0.580          2   2001 Anything      
#>  6          1   2000 Anything        0.580          2   2002 Anything      
#>  7          1   2000 Anything        0.580          3   2000 Anything      
#>  8          1   2000 Anything        0.580          3   2001 Anything      
#>  9          1   2000 Anything        0.580          3   2002 Anything      
#> 10          2   2000 Anything        0.580          1   2000 Anything      
#> # ... with 125 more rows, and 2 more variables: `Other Values` <dbl>,
#> #   dist <dbl>

Создано 07.12.2020 с помощью пакета REPEX (v0.3.0)

person Arthur Yip    schedule 08.12.2020
comment
Большое спасибо! Оно работает! Сначала я все еще сталкивался с некоторыми проблемами с памятью. Наконец, я разделил оба списка фреймов данных по провинциям и использовал ваш код в цикле for. - person Tom; 08.12.2020
comment
Привет, Артур, у меня странная проблема с этим решением. Мне было интересно, знаете ли вы, почему это происходит. По моим фактическим данным, я вижу, что год DT1 совпадает с другим годом DT2, где это должен быть тот же год. Я думал, что группировка предотвратит это, но, видимо, мне что-то не хватает. Я поигрался и с by=, и с group_by, без желаемого результата (в итоге я получаю пустой список). - person Tom; 08.12.2020
comment
если вы используете by в stringdist_join, вы получите результат, который пытается сопоставить все годы по расстоянию между строками. Это даст вам year.dist = 1 для матча 2010 ‹-› 2019 или 2000 ‹-› 2020 и т. Д., Поскольку требуется только одно изменение символа. Вы можете попробовать выполнить точное объединение перед использованием нечеткого объединения или попытаться использовать нечеткое объединение multi_match_by, где вы можете указать == для года и stringdist для муниципалитета и провинции. - person Arthur Yip; 08.12.2020
comment
Спасибо, Артур, попробую утром :) - person Tom; 08.12.2020
comment
мои решения здесь также могут помочь: stackoverflow.com/questions/44383510/ stackoverflow.com/questions/56009863/ stackoverflow.com/questions/58442426/ stackoverflow.com/questions/64321242/ - person Arthur Yip; 08.12.2020
comment
и в этом вы видите, что можете дважды применить top_n или slice_min, чтобы выбрать наилучшие совпадения в соответствии с вашими критериями stackoverflow.com/questions/42749447/ - person Arthur Yip; 08.12.2020