Jak jsem se zmínil v mé připomínky, problémem zde není ani tak rozebrat na character
řetězce jako je definování logiky , aby
- spolupracovník varianty téhož jména (ex.
"Garcia MAC"
, "Lopez Garcia MA"
) podle zástupce štítku ("Lopez-Garcia M"
); a ještě
- vyhněte se házet do jednoho pytle spolu podobné varianty (jako
"Garcia A"
) různé názvy (jako "Andy Garcia"
).
Jako takový, váš nejlepší přístup může být definovat mapping
tabulka pro známé variace na názvy.
Doslovný Mapování
Doslovný mapování zahrnuje psaní každý známá varianta, vedle názvu skutečně představuje.
mapping_lit <- data.frame(
True_Name = c("Adu-Amankwah E", "Smith-Dawson E", "Lopez-Garcia M", "Lopez-Garcia M", "Lopez-Garcia M"),
Variant = c("Adu-Amankwah E", "Smith Dawson E", "Lopez-Garcia M", "Lopez Garcia MA", "Garcia MAC")
)
mapping_lit
#> True_Name Variant
#> 1 Adu-Amankwah E Adu-Amankwah E
#> 2 Smith-Dawson E Smith Dawson E
#> 3 Lopez-Garcia M Lopez-Garcia M
#> 4 Lopez-Garcia M Lopez Garcia MA
#> 5 Lopez-Garcia M Garcia MAC
Jakmile budete mít vaše mapping
jednoduchý dplyr::*_join()
to by mělo stačit
library(dplyr)
# The LEFT JOIN preserves any names without matches, so you can handle them as you wish.
left_join(
df,
mapping_lit,
by = c("names" = "Variant")
)
s tímto výsledkem:
names True_Name
1 Adu-Amankwah E Adu-Amankwah E
2 Smith Dawson E Smith-Dawson E
3 Lopez-Garcia M Lopez-Garcia M
4 Lopez Garcia MA Lopez-Garcia M
5 Garcia MAC Lopez-Garcia M
6 Lopez Garcia MA Lopez-Garcia M
7 Garcia MAC Lopez-Garcia M
Regex Mapování
Pokud jste zručný dost s regulární výrazy, můžete definovat jen jeden regex reprezentovat všechny varianty na každé True_Name
:
mapping_rgx <- data.frame(
True_Name = c("Adu-Amankwah E", "Smith-Dawson E", "Lopez-Garcia M"),
Pattern = c("^(Adu[- ]?)?Amankwah( E)?$", "^(Smith[- ]?)?Dawson( E)?$", "^(Lopez[- ]?)?Garcia( M(AC?)?)?$")
)
mapping_rgx
#> True_Name Pattern
#> 1 Adu-Amankwah E ^(Adu[- ]?)?Amankwah( E)?$
#> 2 Smith-Dawson E ^(Smith[- ]?)?Dawson( E)?$
#> 3 Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
Jakmile budete mít toto mapování, budete potřebovat fuzzyjoin::regex_*_join()
na zápas se varianty
library(fuzzyjoin)
# The LEFT JOIN preserves any names without matches, so you can handle them as you wish.
regex_left_join(
df,
mapping_rgx,
by = c("names" = "Pattern"),
# Account for typos in capitalization.
ignore_case = TRUE
)
s tímto výsledkem:
names True_Name Pattern
1 Adu-Amankwah E Adu-Amankwah E (Adu[- ]?)?Amankwah( E)?
2 Smith Dawson E Smith-Dawson E (Smith[- ]?)?Dawson( E)?
3 Lopez-Garcia M Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
4 Lopez Garcia MA Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
5 Garcia MAC Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
6 Lopez Garcia MA Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
7 Garcia MAC Lopez-Garcia M ^(Lopez[- ]?)?Garcia( M(AC?)?)?$
Varování
Jak jsem také uvedl, možná ne doporučit stringdist
přístup v této situaci. Každý název se liší nejen v pravopisu, ale i ve struktuře. Je docela možné, že dva podobně strukturovaných záznamů pro dva různé lidi
Varianta |
True_Name |
Garciovi |
Andy Garcia |
Garcia MAC |
Lopez-Garcia M |
Lopez-Garcia M |
Lopez-Garcia M |
mají kratší řetězce vzdálenosti, než dělat dvě odlišně strukturované variace na stejné jméno:
# Run the full gamut of methods for 'stringdist::stringdist()'.
methods <- c(
"osa", "lv", "dl", "hamming", "lcs", "qgram",
"cosine", "jaccard", "jw", "soundex"
)
# Display string distances for variants of the same and of different names:
rbind(
# Compare different names.
sapply(X = methods, FUN = function(x) {stringdist::stringdist(
a = "Garcia MAC", b = "Garcia A",
method = x
)}),
# Compare variations on the same name.
sapply(X = methods, FUN = function(x) {stringdist::stringdist(
a = "Garcia MAC", b = "Lopez-Garcia M",
method = x
)})
)
#> osa lv dl hamming lcs qgram cosine jaccard jw soundex
#> [1,] 2 2 2 Inf 2 2 0.08712907 0.2222222 0.06666667 1
#> [2,] 8 8 8 Inf 8 8 0.27831216 0.5333333 0.20952381 1