用条件分隔行

Separate rows with conditions

我有这个数据框 separate_on_condition 有两列:

separate_on_condition <- data.frame(first = 'a3,b1,c2', second = '1,2,3,4,5,6')`

#         first      second
#    1 a3,b1,c2 1,2,3,4,5,6

我怎样才能把它变成:

# A tibble: 6 x 2
  first second
  <chr> <chr> 
1  a     1  
2  a     2
3  a     3  
4  b     4    
5  c     5  
6  c     6

其中:

有没有比在 first 列上使用 rep() 和在 second 列上使用 separate_rows() 更好的方法?

如有任何帮助,我们将不胜感激!

您可以选择以下基础 R 选项

with(
  separate_on_condition,
  data.frame(
    first = unlist(sapply(
      unlist(strsplit(first, ",")),
      function(x) rep(gsub("\d", "", x), as.numeric(gsub("\D", "", x)))
    ), use.names = FALSE),
    second = eval(str2lang(sprintf("c(%s)", second)))
  )
)

这给出了

  first second
1     a      1
2     a      2
3     a      3
4     b      4
5     c      5
6     c      6
  • 创建行号列以说明多行。
  • 在单独的行中拆分 , 上的 second 列。
  • 为每一行提取要重复的数据以及需要重复的次数。
library(dplyr)
library(tidyr)
library(stringr)

separate_on_condition %>%
  mutate(row = row_number()) %>%
  separate_rows(second, sep = ',') %>%
  group_by(row) %>%
  mutate(first = rep(str_extract_all(first(first), '[a-zA-Z]+')[[1]],
                     str_extract_all(first(first), '\d+')[[1]])) %>%
  ungroup %>%
  select(-row)
  
# first second
#  <chr> <chr> 
#1 a     1     
#2 a     2     
#3 a     3     
#4 b     4     
#5 c     5     
#6 c     6     

这是另一种方法:

  1. NA 添加到 first 以获得相同的 length
  2. 使用separate_rows将每个元素排成一行
  3. 使用正则表达式数字 extractfirst 拆分为 firsthelper
  4. 分组和 slicehelper
  5. 中的值
  6. 做一些调整
library(tidyr)
library(dplyr)
separate_on_condition %>%  
    mutate(first = str_c(first, ",NA,NA,NA")) %>% 
    separate_rows(first, second, sep = "[^[:alnum:].]+", convert = TRUE) %>% 
    extract(first, into = c("first", "helper"), "(.{1})(.{1})", remove=FALSE) %>% 
    group_by(second) %>% 
    slice(rep(1:n(), each = helper)) %>% 
    ungroup() %>% 
    drop_na() %>% 
    mutate(second = row_number()) %>% 
    select(first, second)
  first second
  <chr>  <int>
1 a          1
2 a          2
3 a          3
4 b          4
5 c          5
6 c          6