Dplyr: Čistý double-barreled příjmení

0

Otázka

Mám data.rám takových jmen, jako je následující, který má vzorek některá příjmení následuje počáteční (např. Smith S nebo Lopez-Garcia M):

df<-data.frame(names=c("Adu-Amankwah E",
"Smith Dawson E",
"Lopez-Garcia M",
"Lopez Garcia MA",
"Garcia MAC",
"Lopez Garcia MA",
"Garcia MAC"))

Rád bych, aby vytáhnout všechny ty jména s dvouhlavňovou příjmení a udělat malý čištění:

  1. vytáhněte všechny s pomlčkou (-) nebo dvě příjmení (např. Lopez Garcia).
  2. Potřebuji nahradit některou z těchto vlastností: Lopez Garcia MA,Lopez-Garcia MA nebo Garcia MAC s Lopez-Garcia M. A Smith Dawson E by měl být Smith-E. Dawson

Výstup bude vypadat:

df<-data.frame(names=c("Adu-Amankwah E",
"Smith-Dawson E",
"Lopez-Garcia M",
"Lopez-Garcia M",
"Lopez-Garcia M",
"Lopez-Garcia M",
"Lopez-Garcia M"))
dplyr r stringr
2021-11-23 15:57:34
1

Nejlepší odpověď

4

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 mappingjednoduchý 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
2021-11-23 22:40:15

Děkuji moc, tohle je velmi komplexní!!! Pošlu nějakou odměnu, když je k dispozici!
HCAI

@HCAI Děkuji, moc si toho vážím!
Greg

Oh wow, @poskytováním zdravotní péče, to je velkorysá nabídka. Děkuji!!!
Greg

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................