У меня есть столбец dataframe со строкой, которая может включать несколько пробелов. Я хочу использовать separate
из tidyr
(или что-то подобное) в пространстве после первого появления ключевого слова (т. е. fruit_key
в примере данных), чтобы разделить один столбец на два столбца.
Пример данных
df <- structure(list(fruit = c("Apple Orange Pineapple", "Plum Good Watermelon",
"Plum Good Kiwi", "Plum Good Plum Good", "Cantaloupe Melon", "Blueberry Blackberry Cobbler",
"Peach Pie Apple Pie")), class = "data.frame", row.names = c(NA,
-7L))
fruit_key <- c("Apple", "Plum Good", "Cantaloupe", "Blueberry", "Peach Pie")
Ожидаемый результат
fruit Delicious Tasty
1 Apple Orange Pineapple Apple Orange Pineapple
2 Plum Good Watermelon Plum Good Watermelon
3 Plum Good Kiwi Plum Good Kiwi
4 Plum Good Plum Good Plum Good Plum Good
5 Cantaloupe Melon Cantaloupe Melon
6 Blueberry Blackberry Cobbler Blueberry Blackberry Cobbler
7 Peach Pie Apple Pie Peach Pie Apple Pie
Я могу получить часть после ключевого слова с separate
в правильный столбец (например, Tasty
), но не могу получить фактическое ключевое слово для другого столбца (например, Delicious
). Я пробовал несколько раз изменять регулярное выражение, но так и не смог получить правильный результат.
library(tidyr)
separate(df, fruit,
c("Delicious", "Tasty"),
sep = paste(fruit_key, collapse = "|"),
extra = "merge",
remove = FALSE
)
# fruit Delicious Tasty
#1 Apple Orange Pineapple Orange Pineapple
#2 Plum Good Watermelon Watermelon
#3 Plum Good Kiwi Kiwi
#4 Plum Good Plum Good Plum Good
#5 Cantaloupe Melon Melon
#6 Blueberry Blackberry Cobbler Blackberry Cobbler
#7 Peach Pie Apple Pie Apple Pie
Я знаю, что мог бы использовать str_extract
и str_remove
(как показано ниже), но хочу использовать что-то вроде separate
, чтобы сделать это за одну функцию/шаг.
library(tidyverse)
df %>%
mutate(Delicious = str_extract(fruit, paste(fruit_key, collapse = "|")),
Tasty = str_remove(fruit, paste(fruit_key, collapse = "|")))
Если нам нужно использовать separate
с sep
, то создайте поиск регулярного выражения - "(?<=<fruit_key>) "
т. е. разделите пробел, следующий за словом fruit_key, и, поскольку он не векторизован, collapse
в одну строку с |
(str_c
)
library(dplyr)
library(tidyr)
library(stringr)
df %>%
separate(fruit, into = c("Delicious", "Tasty"),
sep = str_c(sprintf("(?<=%s) ", fruit_key), collapse = "|"),
extra = "merge", remove = FALSE)
-выход
fruit Delicious Tasty
1 Apple Orange Pineapple Apple Orange Pineapple
2 Plum Good Watermelon Plum Good Watermelon
3 Plum Good Kiwi Plum Good Kiwi
4 Plum Good Plum Good Plum Good Plum Good
5 Cantaloupe Melon Cantaloupe Melon
6 Blueberry Blackberry Cobbler Blueberry Blackberry Cobbler
7 Peach Pie Apple Pie Peach Pie Apple Pie
Вот аккуратное решение с функцией tidyr
extract
:
library(tidyr)
df %>%
extract(fruit,
into = c("Delicious", "Tasty"),
regex = paste0("(", paste0(fruit_key, collapse = "|"), ")\\s(.*)"),
remove = FALSE)
fruit Delicious Tasty
1 Apple Orange Pineapple Apple Orange Pineapple
2 Plum Good Watermelon Plum Good Watermelon
3 Plum Good Kiwi Plum Good Kiwi
4 Plum Good Plum Good Plum Good Plum Good
5 Cantaloupe Melon Cantaloupe Melon
6 Blueberry Blackberry Cobbler Blueberry Blackberry Cobbler
7 Peach Pie Apple Pie Peach Pie Apple Pie
В аргументе регулярного выражения extract
мы сворачиваем fruit_key
в шаблон чередования, который мы заключаем в круглые скобки, чтобы он распознавался как группа захвата. Вторая группа захвата — это просто то, что следует после пробела.
Насколько я понимаю, вы используете separate
, когда у вас есть четкий шаблон разделения «посередине». И наоборот, с extract
вам не нужна такая четкая и простая точка разделения. То, что вы делаете, это использование групп захвата, т.е. (...)
и группы без захвата за пределами (...)
, вы описываете строку весь абстрактно. В вашем случае регулярное выражение paste0("(", paste0(fruit_key, collapse = "|"), ")\\s(.*)")
исчерпывающе описывает строки в fruits
. Хитрость заключается в том, что вы помещаете в группы захвата то, что хотите извлечь, и не кладете в такие группы захвата то, что хотите отбросить.
Круто, я никогда не использовал это раньше! Итак, я понимаю, что
extract
использует регулярные выражения для захвата групп (так отличается отseparate
). Но когда вы захотите использовать один над другим? Просто пытаюсь понять разницу немного больше.