Как разделить все строки в столбце и включить префикс во все новые данные

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

Итак, что-то вроде «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)

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
746
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вариант 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.

Я думаю, что OP говорит, что префикс (например, PC, VC) и суффикс (например, F, M) должны быть сохранены для каждой из отдельных частей. Это соответствует ожидаемому результату OP, за исключением code_2 в строке 1.

andrew_reece 13.05.2019 03:31

@andrew_reece А, теперь вижу и понимаю! Это будет немного сложнее, чем один звонок separate. Я изучаю это сейчас...

Maurits Evers 13.05.2019 03:42

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>

Только что заметил, что это не совсем так. В тех случаях, когда нет третьего code, суффикс будет повторяться. Сейчас смотрю обновление.

andrew_reece 13.05.2019 03:44

Очень длинное базовое решение 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.

Вот еще вариант с 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>

Другие вопросы по теме