Выяснить, почему сопоставление символов не работает - PullRequest
0 голосов
/ 25 марта 2019

Для данного проекта я вынужден объединить несколько фреймов данных с помощью символьного столбца. Это иногда проблематично из-за, например, замыкающего пробела, но также может быть легко исправлено. Однако в этом случае объединение не работает, и я не могу понять, что отличает символьные значения в столбце, используемом для объединения.

Поскольку в исходном формате проблема не была воспроизведена, вот ссылка , где можно загрузить данные. Это выглядит так:

readRDS("path/sourceA") -> sourceA
sourceA
# A tibble: 1 x 2
  Name                  category
  <chr>                    <dbl>
1 Grundschule Kronsberg        1

readRDS("path/sourceB") -> sourceB
sourceB
# A tibble: 1 x 2
  Name                  value
  <chr>                 <dbl>
1 Grundschule Kronsberg     2

Я хочу объединить эти фреймы данных, используя общую переменную id Name. Как вы можете видеть, кажется, что значение одинаково в обоих кадрах. Однако, когда я применяю любую процедуру присоединения, это происходит:

library(tidyverse)
joined.df <- full_join(sourceA, sourceB, by = "Name")

joined.df
# A tibble: 2 x 3
  Name                  category value
  <chr>                    <dbl> <dbl>
1 Grundschule Kronsberg        1    NA
2 Grundschule Kronsberg       NA     2

Пытаясь выяснить это, я попытался удалить пробел из столбца Name, но, используя стандартную процедуру, смог сделать это только для sourceA. Для sourceB это выглядит так, как будто процедура не удаляет пробелы между "Grundschule" и "Kronsberg".

joined.df %>%
  mutate(Name_test = stringr::str_replace_all(Name, fixed(" "), ""))

# A tibble: 2 x 4
  Name                  category value Name_test            
  <chr>                    <dbl> <dbl> <chr>                
1 Grundschule Kronsberg        1    NA GrundschuleKronsberg 
2 Grundschule Kronsberg       NA     2 Grundschule Kronsberg

Странно, при использовании stringr::str_replace_all(Name, "\\p{WHITE_SPACE}", "") работает:

joined.df %>%
  mutate(Name_test = stringr::str_replace_all(Name, "\\p{WHITE_SPACE}", ""))

# A tibble: 2 x 4
  Name                  category value Name_test           
  <chr>                    <dbl> <dbl> <chr>               
1 Grundschule Kronsberg        1    NA GrundschuleKronsberg
2 Grundschule Kronsberg       NA     2 GrundschuleKronsberg

Я не знаю ничего о том, как поиск в "\\p{WHITE_SPACE}" отличается от fixed(" ") под капотом, но я подумал, что это может быть хорошая подсказка для того, кто это делает.

1 Ответ

0 голосов
/ 25 марта 2019

После довольно обсуждения в комментариях я смог решить проблему.Хотя переменные Name выглядели одинаково (и были проанализированы идентично с помощью dput()), при преобразовании символов в их коды ASCII была небольшая разница:

library(gtools)

asc(sourceA$Name)
      Grundschule Kronsberg
 [1,]                    71
 [2,]                   114
 [3,]                   117
 [4,]                   110
 [5,]                   100
 [6,]                   115
 [7,]                    99
 [8,]                   104
 [9,]                   117
[10,]                   108
[11,]                   101
[12,]                    32
[13,]                    75
[14,]                   114
[15,]                   111
[16,]                   110
[17,]                   115
[18,]                    98
[19,]                   101
[20,]                   114
[21,]                   103

asc(sourceB$Name)
      Grundschule Kronsberg
 [1,]                    71
 [2,]                   114
 [3,]                   117
 [4,]                   110
 [5,]                   100
 [6,]                   115
 [7,]                    99
 [8,]                   104
 [9,]                   117
[10,]                   108
[11,]                   101
[12,]                   194
[13,]                   160
[14,]                    75
[15,]                   114
[16,]                   111
[17,]                   110
[18,]                   115
[19,]                    98
[20,]                   101
[21,]                   114
[22,]                   103

sourceB имеет дополнительный сравниваемый кодsourceA и различные значения в позициях 12 и 13. Используя chr() (также из gtools), я смог преобразовать коды ASCII в символы:

    chr(asc(sourceA$Name))
 [1] "G" "r" "u" "n" "d" "s" "c" "h" "u" "l" "e" " " "K" "r" "o" "n" "s" "b" "e" "r" "g"

chr(asc(sourceB$Name))
 [1] "G" "r" "u" "n" "d" "s" "c" "h" "u" "l" "e" "Â" " " "K" "r" "o" "n" "s" "b" "e" "r" "g"

В sourceB, в строке есть дополнительный Â (десятичный код ASCII 194), и пробел закодирован десятичным 160 вместо 32. Я до сих пор не знаю, почему в сочетании эти два кода ASCII отображались как обычный белыйпробел, но смог решить проблему, просто заменив все пробелы на " "

sourceB <- sourceB %>%
  mutate(Name = stringr::str_replace_all(Name, "\\p{WHITE_SPACE}", " "))

full_join(sourceA, sourceB, by = "Name")
# A tibble: 1 x 3
  Name                  category value
  <chr>                    <dbl> <dbl>
1 Grundschule Kronsberg        1     2

Это (каким-то образом) изменило коды ASCII так, что теперь они совпадают друг с другом:

chr(asc(sourceB$Name))
 [1] "G" "r" "u" "n" "d" "s" "c" "h" "u" "l" "e" " " "K" "r" "o" "n" "s" "b" "e" "r" "g"
...