Разделить на столбец, рассматривая последовательные разделители как один - PullRequest
2 голосов
/ 30 октября 2019

Привет! Я хотел бы разбить один столбец data.frame на несколько столбцов, но с последовательными разделителями, которые рассматриваются как один. Мои входные данные были скопированы из текстового файла, так что это немного путаница с различными разделителями, а иногда один и тот же дублируется несколько раз. В моем примере ниже я использую пробел, запятую, "и" или тире в качестве разделителей, но на самом деле у меня> 6 разных, включая несколько слов ("и" и "вкл").

Я бы обычно использовал tidyr::separate, но у него нет возможности комбинировать последовательные разделители. Попытка составить исчерпывающий список возможных комбинаций для шаблона вскоре становится нелепой, тем более что иногда у меня может быть 4 или 5 пробелов или запятых подряд.

Я предоставил репрезентативный и желаемый вывод (сделанный путем ручного изменения текста, что невозможно в моих реальных данных о тысячах строк) ниже

Данные:

library(tidyr)

testdf <- data.frame(test = c("This string has single spaces",
                              "This  one  has  double  spaces",
                              "This, has, comma,or space,   or ,both",
                              "This,one-, space,- comma -,and-dash"))

Вот коды, которые я пытался использовать до сих пор:

separate(testdf, test, into = letters[1:12], sep = " |,|-|and", fill = "right")

#> Warning: Expected 12 pieces. Additional pieces discarded in 2 rows [3, 4].
#>      a      b   c      d      e     f      g    h      i     j    k    l
#> 1 This string has single spaces  <NA>   <NA> <NA>   <NA>  <NA> <NA> <NA>
#> 2 This        one           has       double      spaces  <NA> <NA> <NA>
#> 3 This        has               comma     or             space          
#> 4 This        one               space                    comma

#sort of starting to work but gets very extensive very fast
separate(testdf, test, into = letters[1:12], sep = "  |, |, | |and|,", fill = "right")

#>      a      b    c      d      e    f     g     h    i     j    k    l
#> 1 This string  has single spaces <NA>  <NA>  <NA> <NA>  <NA> <NA> <NA>
#> 2 This    one  has double spaces <NA>  <NA>  <NA> <NA>  <NA> <NA> <NA>
#> 3 This    has       comma     or            space         or      both
#> 4 This        one-  space      -      comma     -      -dash <NA> <NA>

На основании ответа Грегора, прежде чем я указал, мне нужны разделители слов:


separate(testdf, test, into = letters[1:12], sep = "[ ,-]+", fill = "right")
#>      a      b        c      d      e     f    g    h    i    j    k    l
#> 1 This string      has single spaces  <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 2 This    one      has double spaces  <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> 3 This    has andcomma     or    and space   or both <NA> <NA> <NA> <NA>
#> 4 This    one    space    and  comma   and dash <NA> <NA> <NA> <NA> <NA>


###*Desired Output:*
```r
#>      a      b     c      d      e    f    g
#> 1 This string   has single spaces <NA> <NA>
#> 2 This    one   has double spaces <NA> <NA>
#> 3 This    has comma     or  space   or both
#> 4 This    one space  comma    dash <NA> <NA>

Создано в 2019-10-30 представьте пакет (v0.3.0)

1 Ответ

2 голосов
/ 30 октября 2019

Шаблон регулярного выражения [ ,\\-] соответствует пробелу, запятой или тире. Добавление квантификатора + приводит к совпадению с одним или несколькими пробелами, запятыми или тире. Это шаблон, который вы должны использовать. (Мы избегаем тире -, поскольку внутри скобок это может быть специальный символ, например, "[a-z]" соответствует всем строчным буквам. Убедитесь, что вы избегаете любых других специальных символов регулярных выражений в шаблоне.)

tidyr::separate(testdf, test, into = letters[1:12], sep = "[ ,\\-]+", fill = "right")
#      a      b     c      d      e    f    g    h    i    j    k    l
# 1 This string   has single spaces <NA> <NA> <NA> <NA> <NA> <NA> <NA>
# 2 This    one   has double spaces <NA> <NA> <NA> <NA> <NA> <NA> <NA>
# 3 This    has comma     or  space   or both <NA> <NA> <NA> <NA> <NA>
# 4 This    one space  comma    and dash <NA> <NA> <NA> <NA> <NA> <NA>

Я бы обычно использовал tidyr::separate, но у него нет опции объединения последовательных разделителей

На самом деле, по умолчанию sep объединяет последовательные разделители. Шаблон по умолчанию - [^[:alnum:]]+, это один или несколько не алфавитно-цифровых символов. В этом примере данных все, что не является буквой, является разделителем, поэтому по умолчанию работает просто отлично (но, конечно, ваши реальные данные могут быть более сложными и могут включать знаки препинания, которые вы не хотитеразделить, поэтому подход сверху - это то, что вам нужно).

tidyr::separate(testdf, test, into = letters[1:12], fill = "right")
# same output as above

Если вы хотите быть необычным, используйте stringr::str_count, чтобы подсчитать максимальное количество разделителей и определите into соответственно:

my_pattern = "[ ,\\-]+"
max_delim = max(stringr::str_count(testdf$test, pattern = my_pattern))
tidyr::separate(testdf, test, into = letters[1:(max_delim + 1)],
  fill = "right", sep = my_pattern)
#      a      b     c      d      e    f    g
# 1 This string   has single spaces <NA> <NA>
# 2 This    one   has double spaces <NA> <NA>
# 3 This    has comma     or  space   or both
# 4 This    one space  comma    and dash <NA>

Для многосимвольных матчей вы можете использовать () с | для или, например, "(,| |-|and|incl)+".

...