处理字符串相似性的有效方法?
Efficient way to handle string similarity?
我遇到了一些字符串相似性问题。
我的数据是这样的(原始数据很大):
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
来过滤那些序列号,因为如果会删除 2658358
。
我考虑过使用 stringdist
来查找字符串相似度作为另一个条件(即通过 abs (similarity) >1.5 和 abs (similarity)<0.5 过滤掉)但无法找到一种有效的方法来处理它。它的数据很大并且使用 for 循环是不切实际的。我卡住了一段时间,希望有人能给我一些关于这件事的意见或建议。
以下重现了您的预期输出
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
如果 all Levenshtein SubserialID
和 SerialNumber
之间的距离大于 5,则保留所有条目(每个 SubSerialID
) .如果有一个距离<= 5
,只保留距离最大Date
的那一行。我保留了 dist
列用于调试;您可以使用 select(-dist)
.
删除该列
我不确定这有多普遍。您将不得不使用 Levenshtein 距离阈值(在这种情况下我将其设置为 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)
我遇到了一些字符串相似性问题。
我的数据是这样的(原始数据很大):
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
来过滤那些序列号,因为如果会删除 2658358
。
我考虑过使用 stringdist
来查找字符串相似度作为另一个条件(即通过 abs (similarity) >1.5 和 abs (similarity)<0.5 过滤掉)但无法找到一种有效的方法来处理它。它的数据很大并且使用 for 循环是不切实际的。我卡住了一段时间,希望有人能给我一些关于这件事的意见或建议。
以下重现了您的预期输出
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
如果 all Levenshtein SubserialID
和 SerialNumber
之间的距离大于 5,则保留所有条目(每个 SubSerialID
) .如果有一个距离<= 5
,只保留距离最大Date
的那一行。我保留了 dist
列用于调试;您可以使用 select(-dist)
.
我不确定这有多普遍。您将不得不使用 Levenshtein 距离阈值(在这种情况下我将其设置为 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)