#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
Так:
- сохранить
Festival and Arts
вpreserve <- df[3,]
filter
из рядов сFestival and Arts
- добавьте
id
, чтобы выполнитьseparate_rows
- после этого отфильтруйте строки с
and
- и привязать к
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)))