Как разделить все строки в столбце И включить префикс во все новые данные - PullRequest
6 голосов
/ 13 мая 2019

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

Итак, что-то вроде «PC211 / 212.5 (C) / 664F» имеет префикс «PC» и суффикс «F».Префикс всегда 2 буквы, а суффикс всегда 1, и они всегда символы.За префиксом всегда следует числовой код, а суффиксу всегда предшествует либо число, либо конечные скобки

Мои данные находятся в очень большом фрейме данных, поэтому я хотел бы иметь возможность вызывать егопо колонке.Вот воспроизводимый пример небольшого подмножества данных, с которыми я работаю:

df <- data.frame("code" = c("PC211/212.5(C)/664F", "VC23152(A)/23550F", "PC459/460(B)M", "PC187(A)/664F"), stringsAsFactors = FALSE)

Я бы хотел, чтобы он выглядел примерно так:

df_id_like <- data.frame("code" = c("PC211/212.5(C)/664F", "VC23152(A)/23550F", "PC459/460(B)M", "PC187(A)/664F"), 
"code_1" = c("PC211F", "VC23152(A)F", "PC459M", "PC187F"), 
"code_2" = c("212.5(C)F", "VC23550F", "PC460(B)M", "PC664F"), 
"code_3" = c("PC664F", NA, NA, NA), 
stringsAsFactors = FALSE)

Я думаю, что решение можетМне нужно регулярное выражение, но я полностью открыт для решения, которое не делает!

Ответы [ 4 ]

5 голосов
/ 13 мая 2019

A tidyr опция с использованием separate

library(dplyr)
library(tidyr)
df %>% separate(code, paste0("code_", 1:3), sep = "/", fill = "right", remove = F)
#                 code     code_1   code_2 code_3
#1 PC211/212.5(C)/664F      PC211 212.5(C)   664F
#2   VC23152(A)/23550F VC23152(A)   23550F   <NA>
#3       PC459/460(B)M      PC459  460(B)M   <NA>
#4       PC187(A)/664F   PC187(A)     664F   <NA>

Обратите внимание, что ожидаемый результат не соответствует вашим входным данным. Например, для строки 1 ожидаемый результат для code_3 дает "PC664F", тогда как соответствующая строка ввода - "664F". code_2 для той же строки имеет "212.5(C)F", тогда как входная строка "212.5(C)". Я предполагаю, что это ошибки.


Обновление

Благодаря комментарию @ andrew_reece я (думаю, что) теперь понимаю ваш вопрос. Вот вариант

df %>%
    rowid_to_column("row") %>%
    separate(code, c("prefix", "main", "suffix"), sep = c(2, -1), remove = F) %>%
    separate(main, into = paste0("code_", 1:3), sep = "/", fill = "right") %>%
    gather(key, entry, starts_with("code_")) %>%
    filter(!is.na(entry)) %>%
    unite(entry, prefix, entry, suffix, sep = "") %>%
    spread(key, entry) %>%
    select(-row)

Объяснение: Сначала мы separate добавляем префиксы и суффиксы из code, затем separate отдельные компоненты из основной code части. Мы изменяем форму с широкой на длинную, удаляем NA записи и объединяем каждый code компонент с prefix и suffix перед изменением формы с длинной на широкую.

Это воспроизводит ваш ожидаемый результат за исключением code_2 в строке 1.


Альтернатива

В качестве альтернативного подхода может оказаться более полезным хранить коды с префиксами и суффиксами в столбце list, а не хранить их в широком формате с дополнительными столбцами code_1, code_2 и так далее. Преимущество этого заключается в том, что вам не нужно будет жестко кодировать количество кодов, которое у вас есть в столбце code; следующий подход будет работать для любого количества кодов в code и предполагает только, что

  1. первые 2 символа code определяют prefix
  2. последний символ code - это suffix.

df %>%
    separate(code, c("prefix", "main", "suffix"), sep = c(2, -1), remove = F) %>%
    transmute(
        code,
        codes_as_list = pmap(
            list(prefix, str_split(main, "/"), suffix),
            function(x, y, z) paste0(x, y, z)))
#                 code               codes_as_list
#1 PC211/212.5(C)/664F PC211F, PC212.5(C)F, PC664F
#2   VC23152(A)/23550F       VC23152(A)F, VC23550F
#3       PC459/460(B)M           PC459M, PC460(B)M
#4       PC187(A)/664F           PC187(A)F, PC664F

Обратите внимание, что codes_as_list теперь является столбцом list с правильно заданными / суффиксными кодами, что упрощает работу с элементами с помощью механизма purrr::map.

3 голосов
/ 13 мая 2019

IIUC, это даст вам префикс и суффикс для каждого отдельного столбца:

library(tidyverse)

df %>%
  mutate(prefix = str_extract(code, "^[A-Z]+"),
         suffix = str_extract(code, "[A-Z]$")) %>%
  separate(code, into = c("code_1", "code_2", "code_3"), 
           sep = "/", fill = "right", remove = F) %>%
  mutate_at(vars(matches("_1$")), 
            list(~paste0(., suffix))) %>%
  mutate_at(vars(matches("_2$")), 
            list(~if_else(str_sub(., -1) == suffix, 
                          paste0(prefix, .),
                          paste0(paste0(prefix, .), suffix)))) %>%
  mutate_at(vars(matches("_3$")), 
            list(~if_else(is.na(.), 
                          NA_character_, 
                          paste0(prefix, .)))) %>%
  select(-prefix, -suffix)

                 code      code_1      code_2 code_3
1 PC211/212.5(C)/664F      PC211F PC212.5(C)F PC664F
2   VC23152(A)/23550F VC23152(A)F    VC23550F   <NA>
3       PC459/460(B)M      PC459M   PC460(B)M   <NA>
4       PC187(A)/664F   PC187(A)F      PC664F   <NA>
2 голосов
/ 13 мая 2019

Вот еще один вариант с separate и str_extract_all.Мы создаем шаблон ('pat'), который использует поиск в регулярном выражении, чтобы соответствовать позиции между /, за которым следует число ([0-9]), и вторым шаблоном, чтобы соответствовать позиции символа перед /.Используя str_replace_all, вставьте позицию, совпадающую с 'pat', с первыми двумя символами (substr) строки, а также вставьте позицию перед / с последним символом строки, затем используйте separate дляразбить столбец на три в разделителе /

library(tidyverse)
#pat <- "(?<=\\/)(?=[0-9]+\\(?[A-Z])"
pat <- "(?<=\\/)(?=[0-9])"
pat2 <- "(?=\\/)"
df %>% 
  mutate(code1 = str_replace_all(code, pat, substr(code, 1, 2)) %>% 
  str_replace_all(pat2, substring(code, nchar(code))))%>%
  separate(code1, into = paste0("code_", 1:3), sep="[/]")
#                 code      code_1      code_2 code_3
#1 PC211/212.5(C)/664F      PC211F PC212.5(C)F PC664F
#2   VC23152(A)/23550F VC23152(A)F    VC23550F   <NA>
#3       PC459/460(B)M      PC459M   PC460(B)M   <NA>
#4       PC187(A)/664F   PC187(A)F      PC664F   <NA>
1 голос
/ 13 мая 2019

Очень длинное решение Base R без регулярных выражений

pre <- substr(df$code, 1, 2)
post <- substring(df$code, nchar(df$code))
split_string <- strsplit(df$code, "/")
max_len <- max(lengths(split_string))

df[paste0("code", seq_len(max_len))] <- t(mapply(function(x, y, z) {
    if (length(x) >  2)
     c(paste0(x[1], z), paste0(y, x[-c(1, length(x))], z), paste0(y, x[length(x)]), 
        rep(NA, max_len - length(x)))
    else
     c(paste0(x[1], z), paste0(y, x[length(x)]), rep(NA, max_len - length(x))) 
}, split_string, pre, post))


df
#                 code       code1       code2  code3
#1 PC211/212.5(C)/664F      PC211F PC212.5(C)F PC664F
#2   VC23152(A)/23550F VC23152(A)F    VC23550F   <NA>
#3       PC459/460(B)M      PC459M   PC460(B)M   <NA>
#4       PC187(A)/664F   PC187(A)F      PC664F   <NA>

Сначала найдите префикс и постфикс каждого code, который мы хотим добавить в каждую часть строки, разделите строку на "/" и вычислите количество столбцов, которые нужно добавить (max_len). Используя mapply, мы вставляем pre и post в каждую часть строки соответственно и заполняем пробелы NA.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...