Разделите столбец на разные столбцы в зависимости от метки

У меня есть набор данных, в котором один из столбцов имеет строку в качестве значения. Строка имеет такой аспект: Ф: что угодно; Ф: что угодно; П: что угодно; П: что угодно; С: что угодно; С: что угодно;

Я хочу разделить этот столбец на 3 столбца: один для F, другой для P и еще один для C. Когда имеется более одного F (или P или C), мне нужна отдельная строка для каждого из них (остальная часть столбцы одинаковые).

Как я мог это сделать?

Заранее спасибо!

Пример:

Name Value GOs
Ab1 1000 "F: f1; F: f2; P: p1"
Bb1 2000 "P: p1; F: f1"
Cb1 3000 "C: c1; F: f1"

что я хочу в качестве вывода:

Name Value F P C
Ab1 1000 f1 p1 -
Ab1 1000 f2 p1 -
Bb1 2000 f1 p1 -
Cb1 3000 f1 - c1

Я попробовал с

str_match(a, "F:\\s*(.*?)\\s*;") 

но это работает только для первого совпадения, мне нужны все совпадения.

df <- data.frame(Name = c("A","B","C"),Value = c(10,20,30),GOs= c("F: f1; F: f2; P: p1","P: p1; F: f1","C: c1; F: f1"))

Не могли бы вы отредактировать свой вопрос, включив в него воспроизводимые данные образцов?

jpsmith 18.04.2024 12:31

«Когда есть более одного F (или P или C)», вы имеете в виду вот так? «Ф: что угодно, П: где угодно», та же строка?

Adriano Mello 18.04.2024 12:37

Я имею в виду, что у меня может быть более одной строки для каждой строки, например: «OF: Метаболический; F: транспорт; P: Гидролаза; P: Связывание;»

Isidro Sobrino 18.04.2024 12:39

Пожалуйста, предоставьте примеры данных, например dput(head(YOURDATA))

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

Ответы 3

ОТРЕДАКТИРОВАНО:

library(tidyverse)
df %>%
  separate_rows(GOs, sep = "; ") %>%
  extract(GOs,
          into = c("X","content"),
          regex = "(.)\\W+(.+)") %>%
  pivot_wider(
              names_from = X, values_from = content,
              # add to suppress warning:
              values_fn = list) %>%
  unnest(c("F", "P", "C"))
# A tibble: 4 × 5
  Name  Value F     P     C    
  <chr> <dbl> <chr> <chr> <chr>
1 A        10 f1    p1    NA   
2 A        10 f2    p1    NA   
3 B        20 f1    p1    NA   
4 C        30 f1    NA    c1  

Данные:

df <- data.frame(Name = c("A","B","C"),
                 Value = c(10,20,30),
                 GOs= c("F: f1; F: f2; P: p1","P: p1; F: f1","C: c1; F: f1"))

Обновлено еще раз:

В качестве альтернативы рассмотрим следующую структуру вывода:

df %>%
  separate_rows(GOs, sep = "; ") %>%
  extract(GOs,
          into = c("X","content"),
          regex = "(.)\\W+(.+)") %>%
  pivot_wider(names_from = X, values_from = content, values_fn = toString)
# A tibble: 3 × 5
  Name  Value F      P     C    
  <chr> <dbl> <chr>  <chr> <chr>
1 A        10 f1, f2 p1    NA   
2 B        20 f1     p1    NA   
3 C        30 f1     NA    c1 

Это решает проблему разделения столбца, но другая проблема заключается в том, что в одной строке может быть более одного F, например: «F: значение 1; F: значение 2», и мне нужно, чтобы они были в разных ряды.

Isidro Sobrino 18.04.2024 12:57

Пожалуйста, предоставьте примеры данных, например dput(head(YOURDATA))

Chris Ruehlemann 18.04.2024 12:58

Если повторяется более одной категории, появляется эта ошибка: Ошибка в unnest(): ! В строке 1 невозможно преобразовать ввод размера 3 в размер 2. Например, я получил эту ошибку с этим набором данных: df <- data.frame( Name = c("A","B"), Value = c(10,20), GOs= c("C:e; F:n; F:D; F:D; P:D; P:h","F:t; F:v; F:l; F:m; P:o") )

Isidro Sobrino 18.04.2024 14:31

См. новое решение в редактировании, которое применимо к обоим образцам данных.

Chris Ruehlemann 18.04.2024 15:14
Ответ принят как подходящий

Для обновленного примера:

library(tidyverse)

df <- data.frame(
  Name = c("A", "B"),
  Value = c(10, 20),
  GOs = c("C:e; F:n; F:D; F:D; P:D; P:h", "F:t; F:v; F:l; F:m; P:o")
)

df |> 
  separate_longer_delim(GOs, delim = ";") |> 
  separate_wider_delim(GOs, delim = ":", names_sep = ":") |> 
  mutate(across(everything(), str_squish), row = row_number()) |> 
  pivot_wider(names_from = `GOs:1`, values_from = `GOs:2`, values_fn = list) |> 
  unnest(c("C", "F", "P"))
#> # A tibble: 11 × 6
#>    Name  Value   row C     F     P    
#>    <chr> <chr> <int> <chr> <chr> <chr>
#>  1 A     10        1 e     <NA>  <NA> 
#>  2 A     10        2 <NA>  n     <NA> 
#>  3 A     10        3 <NA>  D     <NA> 
#>  4 A     10        4 <NA>  D     <NA> 
#>  5 A     10        5 <NA>  <NA>  D    
#>  6 A     10        6 <NA>  <NA>  h    
#>  7 B     20        7 <NA>  t     <NA> 
#>  8 B     20        8 <NA>  v     <NA> 
#>  9 B     20        9 <NA>  l     <NA> 
#> 10 B     20       10 <NA>  m     <NA> 
#> 11 B     20       11 <NA>  <NA>  o

Created on 2024-04-18 with reprex v2.1.0

Если повторяется более одной категории, появляется эта ошибка: Ошибка в unnest(): ! В строке 1 невозможно преобразовать ввод размера 3 в размер 2. Например, я получил эту ошибку с этим набором данных: df <- data.frame( Name = c("A","B"), Value = c(10,20), GOs= c("C:e; F:n; F:D; F:D; P:D; P:h","F:t; F:v; F:l; F:m; P:o") )

Isidro Sobrino 18.04.2024 14:32

Я скорректировал его для обновленного примера. Мне нужно было добавить номер строки. При необходимости вы можете удалить это с помощью |> select(-row).

Carl 18.04.2024 15:06

Чтобы избежать изменения формы, которое может быть медленным, вы можете сначала извлечь имена столбцов и значения, используя gregexpr/regmatches. С помощью столбцов unique создайте array без строк и merge его к элементам списка, затем merge все вместе, наконец cbind.

> r <- lapply(c(cn='(.)(?=\\:)', v='(?<=\\:\\s)(.\\d)'), \(x) 
+             regmatches(df$GOs, gregexpr(x, df$GOs, perl=TRUE)))
> u <- unique(unlist(r$cn))
> a <- array(dim=c(0, length(u)), dimnames=list(NULL, u))
> Map(cbind, Name=df$Name, Value=df$Value, 
+     Map(\(x, y) split(x, y), r$v, r$cn) |>
+       lapply(do.call, what='data.frame') |> 
+       lapply(merge, a, all=TRUE)) |> 
+   Reduce(f=rbind)
  Name Value  F    P    C
1  Ab1  1000 f1   p1 <NA>
2  Ab1  1000 f2   p1 <NA>
3  Bb1  2000 f1   p1 <NA>
4  Cb1  3000 f1 <NA>   c1

Данные:

> dput(df)
structure(list(Name = c("Ab1", "Bb1", "Cb1"), Value = c(1000L, 
2000L, 3000L), GOs = c("F: f1; F: f2; P: p1", "P: p1; F: f1", 
"C: c1; F: f1")), class = "data.frame", row.names = c(NA, -3L
))

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