У меня есть фрейм данных с длинным столбцом «комментариев», который включает полуструктурированную информацию о присутствии видов в нескольких зонах для разных участков исследования. Схема обычно выглядит примерно так:
Ниже приведена небольшая часть моих данных. Обратите внимание, что могут быть указаны не все 5 зон. Это когда вид не был обнаружен для данной конкретной зоны. Это не редкость для Зоны 1, но Зона 4 почти всегда присутствует в списке. Другими словами, я считаю, что имею дело с неравной длиной совпадающих групп.
Я хочу использовать seperate_wider_regex, чтобы разделить столбец на два столбца и несколько строк. Конечный результат примерно такой:
Затем я могу повернуть фрейм данных так, чтобы каждая зона получила свой столбец с pivot_wider
. Я могу сопоставить все зоны в строке с помощью следующего регулярного выражения: "[1-4][ab]?[:]?"
Двоеточие (:) обычно присутствует в списках видов, но не всегда. Я также могу сопоставить все между этими двумя шаблонами, за исключением зоны 4, поскольку здесь нет шаблона, который мог бы завершить сопоставление. Я думал, что смогу сделать что-то вроде этого, но это тоже не работает: ".+?(?=[1-4][ab]?:)|(.*)"
Моим идеальным решением было бы использование пакетов из Tidyverse. Вот небольшая часть моих данных:
library(tidyr)
sample_df <- structure(list(site = 1:2, comment = c("2a: species A, species B 2b: species A, species C 3: species C, species D 4: species A, species B, species C",
"2a: species A, species B, species D 2b: species B 3: species C 4: species C, species D, species E"
)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"
))
Вот возможный вариант, в котором str_extract_all
и unnest_longer
сначала используются для создания строк для каждой зоны, а затем используется separate_wider_regex
для разделения строки на zone
и Species
:
sample_df <- structure(list(site = 1:2, comment = c(
"2a: gele lis, waterzuring 2b: pitrus, witbol 3: witbol, ruw beemd 4: ruw beemd, raaigras, witbol",
"2a: gele lis, pitrus, mannagras 2b: pitrus 3: gestreepte witbol 4: gestreepte witbol, engels raai, veld/plat beemd"
)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"))
library(tidyverse)
sample_df |>
mutate(
comment = str_extract_all(comment, "\\d+[a-z]?:[^\\d]*")
) |>
unnest_longer(comment) |>
separate_wider_regex(
comment,
patterns = c(zone = "^\\d+[a-z]?", ":\\s?", Species = ".*$")
) |>
mutate(
Species = str_trim(Species)
)
#> # A tibble: 8 × 3
#> site zone Species
#> <int> <chr> <chr>
#> 1 1 2a gele lis, waterzuring
#> 2 1 2b pitrus, witbol
#> 3 1 3 witbol, ruw beemd
#> 4 1 4 ruw beemd, raaigras, witbol
#> 5 2 2a gele lis, pitrus, mannagras
#> 6 2 2b pitrus
#> 7 2 3 gestreepte witbol
#> 8 2 4 gestreepte witbol, engels raai, veld/plat beemd
Вы можете попробовать
sample_df %>%
mutate(comment = str_split(comment, "\\s(?=\\S+:)")) %>%
unnest(comment) %>%
separate_wider_regex(comment, c(zone = "[^:]+", ":\\s+", species = ".*"))
что дает
# A tibble: 8 × 3
site zone species
<int> <chr> <chr>
1 1 2a species A, species B
2 1 2b species A, species C
3 1 3 species C, species D
4 1 4 species A, species B, species C
5 2 2a species A, species B, species D
6 2 2b species B
7 2 3 species C
8 2 4 species C, species D, species E
Разделите комментарии на строки. Затем разделите каждый комментарий на зоны и виды и обрежьте пробелы по краям.
library(dplyr)
library(tidyr)
sample_df %>%
separate_rows(comment, sep = " (?=[1-4][ab]?[:]?) *") %>%
separate(comment, c("zone", "species"), sep = ":") %>%
mutate(species = trimws(species))
предоставление
# A tibble: 8 × 3
site zone species
<int> <chr> <chr>
1 1 2a species A, species B
2 1 2b species A, species C
3 1 3 species C, species D
4 1 4 species A, species B, species C
5 2 2a species A, species B, species D
6 2 2b species B
7 2 3 species C
8 2 4 species C, species D, species E