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

#r #split

Вопрос:

Проблема

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

Репрекс

Мой начальный набор данных:

 media <- c("TV, Radio and Games", "Theatre, Festival", "Festival and Arts", "TV", "Theatre", "Radio")
type <- c("Indoors", "Outdoors", "Outdoors", "Indoors", "Outdoors", "Indoors")

df <- as.data.frame(cbind(media, type))
df

#   media                type
# 1 TV, Radio and Games    Indoors
# 2   Theatre, Festival    Outdoors
# 3   Festival and Arts    Outdoors
# 4                  TV    Indoors
# 5             Theatre    Outdoors
# 6               Radio    Indoors
 

Желаемый результат

 media2 <- c("TV", "Radio", "Games", "Theatre", "Festival", "Festival and Arts", "TV", "Theatre", "Radio")
type2 <- c("Indoors", "Indoors", "Indoors", "Outdoors", "Outdoors", "Outdoors", "Indoors", "Outdoors", "Indoors")

df2 <- cbind(media2, type2)
df2

#      media2              type2     
# [1,] "TV"                "Indoors" 
# [2,] "Radio"             "Indoors" 
# [3,] "Games"             "Indoors" 
# [4,] "Theatre"           "Outdoors"
# [5,] "Festival"          "Outdoors"
# [6,] "Festival and Arts" "Outdoors"
# [7,] "TV"                "Indoors" 
# [8,] "Theatre"           "Outdoors"
# [9,] "Radio"             "Indoors" 
 

Попытка Решения

 df3 <- df %>% 
  tidyr::separate(media, c("media1", "media2"), ", ") %>% 
  tidyr::pivot_longer(1:2, names_to = "media_type", values_to = "media") %>% 
  select(media, type) %>% 
  filter(!is.na(media))

#   media             type    
# 1 TV                Indoors 
# 2 Radio and Games   Indoors 
# 3 Theatre           Outdoors
# 4 Festival          Outdoors
# 5 Festival and Arts Outdoors
# 6 TV                Indoors 
# 7 Theatre           Outdoors
# 8 Radio             Indoors 
 

Это отчасти помогает мне в этом, но я также хочу, чтобы «Радио и игры» разделились, но не «Фестиваль и искусство». Я не могу разделить его с помощью » и «, так как это разделило бы их обоих.

Комментарии:

1. Не могли бы вы описать свои условия, почему «Радио и игры» должны быть разделены, а «Фестиваль и искусство» — нет?

Ответ №1:

Вы могли бы использовать tidyverse подход:

 library(dplyr)
library(tidyr)
library(stringr)

df %>% 
  mutate(media = ifelse(str_detect(media, ","),
                        str_split(media, pattern = "\s*(,|and)\s*"),
                        media)) %>% 
  unnest(media)
 

Это возвращает

 # A tibble: 9 x 2
  media             type    
  <chr>             <chr>   
1 TV                Indoors 
2 Radio             Indoors 
3 Games             Indoors 
4 Theatre           Outdoors
5 Festival          Outdoors
6 Festival and Arts Outdoors
7 TV                Indoors 
8 Theatre           Outdoors
9 Radio             Indoors 
 

Комментарии:

1. Я исправил ошибку. Пропустил Festival and Arts часть вопроса об операции.

2. Прекрасное регулярное выражение, Мартин, Девочка! 1.

3. Это сработало прекрасно. Итак, прав ли я, предполагая, что этот метод исключает «Фестиваль и искусство», только разделяя эти клетки запятыми в них?

4. ДА. Я ищу строки, содержащие»,», и разделяю только их, но затем использую», » и «и».

Ответ №2:

Вот обходной путь tidyverse:

Проблема в Festival and Arts том, что это содержимое и, в противном случае это было бы просто seperate_rows

Так:

  1. сохранить Festival and Arts в preserve <- df[3,]
  2. filter из рядов с Festival and Arts
  3. добавьте id , чтобы выполнить separate_rows
  4. после этого отфильтруйте строки с and
  5. и привязать к preserve
 library(dplyr)
library(tidyr)

preserve <- df[3,]

df %>% 
    filter(!grepl('Festival and Arts', media)) %>% 
    mutate(id = row_number()) %>% 
    separate_rows(media, id, sep = "[^[:alnum:].] ", convert = TRUE) %>% 
    filter(!grepl('and', media)) %>% 
    bind_rows(preserve) %>% 
    select(-id)
 

выход:

 media             type    
  <chr>             <chr>   
1 TV                Indoors 
2 Radio             Indoors 
3 Games             Indoors 
4 Theatre           Outdoors
5 Festival          Outdoors
6 TV                Indoors 
7 Theatre           Outdoors
8 Radio             Indoors 
9 Festival and Arts Outdoors
> 
 

Ответ №3:

Вариант будет заключаться в том, чтобы оглянуться назад, если Искусство следует и использует (?! Arts) .

 x <- strsplit(df$media, "\s*(,|and(?! Arts))\s*", perl=TRUE)
data.frame(media=unlist(x), type=rep(df$type, lengths(x)))
#              media     type
#1                TV  Indoors
#2             Radio  Indoors
#3             Games  Indoors
#4           Theatre Outdoors
#5          Festival Outdoors
#6 Festival and Arts Outdoors
#7                TV  Indoors
#8           Theatre Outdoors
#9             Radio  Indoors
 

Или разделять только те, у которых есть хотя бы один , .

 i <- grepl(",", df$media)
x <- ifelse(i, str_split(df$media, pattern = "\s*(,|and)\s*"), df$media)
data.frame(media=unlist(x), type=rep(df$type, lengths(x)))