, Это работает, потому что nomatch = 0 отбрасывает несопоставленные случаи / NA, а which = TRUE возвращает только номера строк DT1.

родолжениеэто вопрос, где принятый ответ показал пример сопоставления упражнения с использованиемdata.tableвключая неравные условия.

Фон

Основная настройка заключается в том, что у нас естьDT1 с образцом деталей людей, иDT2, которая является своего рода главной базой данных. И цель состоит в том, чтобы выяснить, является ли каждый человек вDT1 соответствует хотя бы одной записи вDT2.

Сначала мы инициализируем столбец, который будет указывать на соответствиеFALSEчтобы его значения могли быть обновлены доTRUE всякий раз, когда совпадение найдено.

DT1[, MATCHED := FALSE]

Для обновления столбца используется следующее общее решение:

DT1[, MATCHED := DT2[.SD, on=.(Criteria), .N, by=.EACHI ]$N > 0L ]

Теоретически выглядит (и должно работать) нормально. ПодвыражениеDT2[.SD, on=.(Criteria), .N, by=.EACHI] создает вложенную таблицу с каждой строкой изDT1и вычисляетN столбец, который является количеством совпадений для этой строки, найденной вDT2, Тогда всякий раз, когдаN больше нуля, значениеMATCHED вDT1 обновляется доTRUE.

Он работает как задумано в тривиальномвоспроизводимый пример, Но я столкнулся с неожиданным поведением, используя его с реальными данными, и не могу докопаться до сути. Я могу что-то упустить или это может быть ошибка. К сожалению, я не могу привести минимальный воспроизводимый пример, потому что данные большие, и они отображаются только в больших данных. Но я постараюсь документировать это как можно лучше.

Неожиданное поведение или ошибка

Что помогло заметить это, так это то, что по исторической причине совпадения нужно искать в двух отдельных базах данных, и, следовательно, в фильтре!(MATCHED) было добавлено в выражение для обновления только тех значений, которые еще не были сопоставлены:

DT1[!(MATCHED), MATCHED := DT2[.SD, on=.(Criteria), .N, by=.EACHI ]$N > 0L ]

Затем я заметил, что если линия будет перезапущена несколько раз, при каждом последующем прогоне будет появляться все больше и больше совпадений, которые не были сопоставлены в предыдущих прогонах. (Ничего общего с отдельными базами данных, каждый запуск соответствует DT2).

Первый забег:

   MATCHED       N
1:   FALSE 3248007
2:    TRUE 2379514

Второй прогон:

   MATCHED       N
1:   FALSE 2149648
2:    TRUE 3477873

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

Например, вот одна запись изDT1:

         DATE FORENAME SURNAME
1: 2016-01-01     JOHN   SMITH

И подходящая запись от DT2:

   START_DATE EXPIRY_DATE FORENAME SURNAME
1: 2015-09-09  2017-05-01     JOHN   SMITH

Запуск только одного подвыражения (описанного выше) вне основного выражения для просмотраN числа, мы видим, что это не приводит к совпадению, когда это должно (N=0). (Вы также можете отметить, чтоSTART_DATE а такжеEND_DATE взять на себя стоимостьDATE на выходе, но это совсем другая проблема).

SUB <- DF2[DF1, on=.(FORENAME, SURNAME, START_DATE <= DATE, EXPIRY_DATE >= DATE), .N, by=.EACHI]
SUB[FORENAME=="JOHN" & "SURNAME=="SMITH"]

   FORENAME SURNAME START_DATE EXPIRY_DATE N
1:     JOHN   SMITH 2016-01-01  2016-01-01 0

Однако ошибочное поведение состоит в том, что результат зависит от того, какие другие строки присутствуют вDF1, Например, предположим, что я знаю, чтоJOHN SMITHномер строки вDF1 149 и фильтрDF1 только в этот ряд:

DF2[DF1[149], on=.(FORENAME, SURNAME, START_DATE <= DATE, EXPIRY_DATE >= DATE), .N, by=.EACHI]

   FORENAME SURNAME START_DATE EXPIRY_DATE N
1:     JOHN   SMITH 2016-01-01  2016-01-01 1

Во-вторых, я также заметил, что ошибочное поведение возникает только с более чем одним неравным критерием в условиях. Если условияon=.(FORENAME, SURNAME, START_DATE <= DATE), между прогонами больше нет различий, и все строки в первый раз выглядят корректно.

К сожалению, чтобы решить реальную проблему, ядолжен иметь несколько неравных условий соответствия. Не только для того, чтобыDT1«sDATE междуDT2«sSTART_DATE а такжеEND_DATEс, но и этоDT1«sCHECKING_DATE доDT2«sEFFECTIVE_DATE, и т.д.

Обобщить

Неэкви присоединяется вdata.table вести себя некорректно, когда:

Некоторые строки присутствуют / отсутствуют в одной из таблиц

А ТАКЖЕ

Более одного неравного условия

Обновление: воспроизводимый пример

set.seed(123)
library(data.table)
library(stringi)

n <- 100000

DT1 <- data.table(RANDOM_STRING = stri_rand_strings(n, 5, pattern = "[a-k]"),
                  DATE = sample(seq(as.Date('2016-01-01'), as.Date('2016-12-31'), by="day"), n, replace=T))

DT2 <- data.table(RANDOM_STRING = stri_rand_strings(n, 5, pattern = "[a-k]"),
                  START_DATE = sample(seq(as.Date('2015-01-01'), as.Date('2017-12-31'), by="day"), n, replace=T))

DT2[, EXPIRY_DATE := START_DATE + floor(runif(1000, 200,300))]

#Initialization
DT1[, MATCHED := FALSE]

#First run
DT1[!(MATCHED), MATCHED := DT2[.SD, on=.(RANDOM_STRING, START_DATE <= DATE, EXPIRY_DATE >= DATE), .N, by=.EACHI ]$N > 0L ]
DT1[, .N, by=MATCHED]

   MATCHED     N
1:   FALSE 85833
2:    TRUE 14167

#Second run
DT1[!(MATCHED), MATCHED := DT2[.SD, on=.(RANDOM_STRING, START_DATE <= DATE, EXPIRY_DATE >= DATE), .N, by=.EACHI ]$N > 0L ]
DT1[, .N, by=MATCHED]

   MATCHED     N
1:   FALSE 73733
2:    TRUE 26267

#And so on with subsequent runs...

Ответы на вопрос(0)

Ваш ответ на вопрос