如何在复杂数据情况下进行行分割

3

实际上,这个问题并不是我最初提出的。这个问题促使我将其简化成一个简单的情况。

因此,我需要根据当前情况中的分隔符(;)将输入到单元格(列中)的数据分离为单独的行。可以使用tidyr::separate_rows()轻松完成此操作。几乎每一列中的数据已经被连接在一起。现在有两个问题:

  1. 可能会有用()括起来但用;分隔的文本,例如(text_A;text_B),这些文本要保持连接而不是分开。
  2. 在每行的不同列之间,连接次数可能不均匀。在这种情况下,该行应被分成等于最大连接次数的每个单独的行。对于其他连接较少的列,最后的文本值可能只是重复的。

以下是一个可重现的示例:

input <- data.frame(
  stringsAsFactors = FALSE,
  col_1 = c("A", "B", "C"),
  Col_2 = c("Text_A;Text_B","Text_C","Text_D;(Text_E;Text_F)"),
  Col_3 = c("Text_1", "Text_2;Text_3", "Text_4"),
  Col_4 = c("Text_a;(Text_b;Text_c);(Text_d;Text_dd)","Text_e","Text_f;Text_g")
)

input
  col_1                  Col_2         Col_3                                   Col_4
1     A          Text_A;Text_B        Text_1 Text_a;(Text_b;Text_c);(Text_d;Text_dd)
2     B                 Text_C Text_2;Text_3                                  Text_e
3     C Text_D;(Text_E;Text_F)        Text_4                           Text_f;Text_g

期望的输出如下所示:
output
#>   col_1           Col_2  Col_3            Col_4
#> 1     A          Text_A Text_1           Text_a
#> 2     A          Text_B Text_1  (Text_b;Text_c)
#> 3     A          Text_B Text_1 (Text_d;Text_dd)
#> 4     B          Text_C Text_2           Text_e
#> 5     B          Text_C Text_3           Text_e
#> 6     C          Text_D Text_4           Text_f
#> 7     C (Text_E;Text_F) Text_4           Text_g

除了 tidyverse 以外的答案也是可以接受的。

2个回答

2

以下是我的方法,假设您的列中没有序列"<sep>"

input %>%
  mutate(across(-col_1,
                ~ str_replace_all(., "\\([^)]*\\)",
                                  \(x) str_replace_all(x, ";", "<sep>")))) %>%
  pmap(\(...) {
    args <- list(...)
    entries <- map(args[-1], ~ first(str_split(., ";")))
    map(entries, \(e) {
      c(e, rep(e[length(e)], do.call(max, map(entries, length)) - length(e)))
    }) %>%
    bind_rows() %>%
    bind_cols(args[1], .)
  }) %>%
  bind_rows() %>%
  mutate(across(-col_1, ~ str_replace_all(., "<sep>", ";")))

返回:

# A tibble: 7 x 4
  col_1 Col_2           Col_3  Col_4
  <chr> <chr>           <chr>  <chr>
1 A     Text_A          Text_1 Text_a
2 A     Text_B          Text_1 (Text_b;Text_c)
3 A     Text_B          Text_1 (Text_d;Text_dd)
4 B     Text_C          Text_2 Text_e
5 B     Text_C          Text_3 Text_e
6 C     Text_D          Text_4 Text_f
7 C     (Text_E;Text_F) Text_4 Text_g

1
谢谢@ktiu。实际上比之前的答案更好。:). 如果还有更多的策略/答案,我会等待,否则我会接受这个 :) - AnilGoyal

1
提取所需组。计算每行的最大长度并填充值。
input <- input %>%
  mutate(across(everything(), str_extract_all, pattern = "(\\([^\\(\\)]+\\)|[^;]+)")) 

input_l <- pmap_int(input, ~max(map_int(list(...), length)))

input %>%
  split(seq_len(nrow(.))) %>%
  map(flatten) %>%
  map2_dfr(input_l, function(row, l) map_dfr(row, ~c(.x, rep(last(.x), l - length(.x))))) 

这将产生以下输出。
  col_1 Col_2           Col_3  Col_4                
  <chr> <chr>           <chr>  <chr>                
1 A     Text_A          Text_1 Text_a               
2 A     Text_B          Text_1 (Text_b;Text_c)      
3 A     Text_B          Text_1 (Text_d;Text_dd)
4 B     Text_C          Text_2 Text_e               
5 B     Text_C          Text_3 Text_e               
6 C     Text_D          Text_4 Text_f               
7 C     (Text_E;Text_F) Text_4 Text_g 

第三行第二列应该是文本B而不是文本A。最后一个值要重复。让我检查你的策略并回复。 - AnilGoyal
1
这将从开头开始重复值。为什么只复制最后一个值?例如,当您有1、2、3时,需要将其扩展到长度5,应该如何处理? - det
这就是要求。例如,在五行中,1、2、3的示例应为1、2、3、3、3。 - AnilGoyal
那是正则表达式中的拼写错误。 - det
1
现在,括号内可以放置超过2个值。 - det

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接