Эффективный способ обработки сходства строк? - PullRequest
3 голосов
/ 18 февраля 2020

Я застрял на некоторых вопросах сходства строк.

Вот так выглядят мои данные (исходные данные огромны):

SerialNumber                SubSerialID            Date

AGCC0775CFNDA1040TMT775     AVCC0775CFNDA1040     2018/01/08
AGCC0775CFNDA1040           AVCC0775CFNDA1040     2015/12/28
AGCC0775CFNDA10407EC        AVCC0775CFNDA1040     2018/03/17
CH~MT765E~C0765HFNCC1056    BGDC0865HFNKG1043     2019/01/07
2658358                     BGDC0865HFNKG1043     2018/08/09
MT765E~C0765KFNCD1044       C0765KFNCD10          2015/04/07
187A126                     C0765KFNCD10          2017/11/31

...

Моя цель:

SerialNumber                SubSerialID            Date 

AGCC0775CFNDA10407EC        AVCC0775CFNDA1040     2018/03/17
CH~MT765E~C0765HFNCC1056    BGDC0865HFNKG1043     2019/01/07
2658358                     BGDC0865HFNKG1043     2018/08/09
MT765E~C0765KFNCD1044       C0765KFNCD10          2015/04/07
187A126                     C0765KFNCD10          2017/11/31

...

Серийные номера AGCC0775CFNDA1040TMT775, AGCC0775CFNDA1040 и AGCC0775CFNDA10407EC - это то же самое, но они вызваны ошибками. Я хочу сохранить AGCC0775CFNDA10407EC, потому что в нем записана самая последняя дата. Однако я не могу использовать SubSerialID и Date напрямую для фильтрации этих серийных номеров, потому что if удалит 2658358.

Я думал об использовании stringdist, чтобы найти сходство строк в качестве другого условия (т. Е. Отфильтровать по abs (сходство)> 1.5 и abs (сходство) <0.5), но не могу найти эффективный способ справиться с ним. , Данные огромны и используются для l oop - непрагматично c. Я застрял на некоторое время и, надеюсь, кто-нибудь может дать мне совет или предложение по этому вопросу. </p>

1 Ответ

3 голосов
/ 18 февраля 2020

Следующее воспроизводит ваш ожидаемый результат

library(dplyr)
library(purrr)
df %>%
    mutate(Date = as.Date(Date)) %>%
    mutate_if(is.factor, as.character) %>%
    mutate(dist = map2_dbl(SerialNumber, SubSerialID, adist)) %>%
    group_by(SubSerialID) %>%
    filter(all(dist > 5) | Date == max(Date)) %>%
    ungroup()
## A tibble: 5 x 4
#  SerialNumber             SubSerialID       Date        dist
#  <chr>                    <chr>             <date>     <dbl>
#1 AGCC0775CFNDA10407EC     AVCC0775CFNDA1040 2018-03-17     4
#2 CH~MT765E~C0765HFNCC1056 BGDC0865HFNKG1043 2019-01-07    15
#3 2658358                  BGDC0865HFNKG1043 2018-08-09    15
#4 MT765E~C0765KFNCD1044    C0765KFNCD10      2015-04-07     9
#5 187A126                  C0765KFNCD10      2017-11-30    11

Идея состоит в том, чтобы сохранить все записи (на SubSerialID), если все Левенштейновские расстояния между SubserialID и SerialNumber больше 5. Если есть одно расстояние <= 5, сохраняйте только строку с наибольшим Date. Я сохранил столбец dist для отладки; Вы можете удалить столбец с помощью select(-dist).

Я не уверен, насколько это обобщенно. Вам придется поиграться с порогом расстояния Левенштейна (в данном случае я установил 5).


Пример данных

df <- read.table(text =
"SerialNumber                SubSerialID            Date

AGCC0775CFNDA1040TMT775     AVCC0775CFNDA1040     2018/01/08
AGCC0775CFNDA1040           AVCC0775CFNDA1040     2015/12/28
AGCC0775CFNDA10407EC        AVCC0775CFNDA1040     2018/03/17
CH~MT765E~C0765HFNCC1056    BGDC0865HFNKG1043     2019/01/07
2658358                     BGDC0865HFNKG1043     2018/08/09
MT765E~C0765KFNCD1044       C0765KFNCD10          2015/04/07
187A126                     C0765KFNCD10          2017/11/30", header = T)
...