Использованиеdependent_wider_regex для создания новой строки для каждого совпадения в R

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

Сайт Комментарий 1 1: вид A, вид B 2a: вид A, вид C 4: вид A 2 2a: вид B 2b: вид A 4: вид C

Ниже приведена небольшая часть моих данных. Обратите внимание, что могут быть указаны не все 5 зон. Это когда вид не был обнаружен для данной конкретной зоны. Это не редкость для Зоны 1, но Зона 4 почти всегда присутствует в списке. Другими словами, я считаю, что имею дело с неравной длиной совпадающих групп.

Я хочу использовать seperate_wider_regex, чтобы разделить столбец на два столбца и несколько строк. Конечный результат примерно такой:

Сайт Зона Разновидность 1 1 вид А, вид Б 1 2а вид А, вид С 1 4 вид А 2 2а вид Б 2 2б вид А 2 4 вид С

Затем я могу повернуть фрейм данных так, чтобы каждая зона получила свой столбец с 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"
))

2
55
3

Ответы:

Вот возможный вариант, в котором 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