1

脚本需要:

a) 合并相邻行中的文本,相邻行的数量可能会有所不同,要合并的行的分组由第一行前面加 NA 和最后一行后面加 NA 确定,

b) 保留行 ID 以供将来检查

c) 保留与要组合的每一相邻行中的一行相关联的数值变量

d) 保留整体秩序

之前和之后的表

我使用 for 循环和与 dplyr 和 stringer 争吵的大量数据实现了这一点。

for 循环是不优雅的,因为我正在努力使用按顺序识别相邻行的逻辑。这并不重要,因为分组变量只是一个帮手——但这让我很恼火。

我还想知道是否有一种更有效的方法可以完全做到这一点,比如使用 rowwise 和 mutate with lead 或 lag。

任何指导或指示将不胜感激。

library(tidyverse)

tib <- tibble(id = 1:11,
              var = c("a", NA, NA, "b", "c" , NA, "d", NA, NA, NA, "e"),
              txt = c( NA, "the", "cat",  NA,  NA, "sat", NA, "on", "the", "mat", NA),
              nr = c( NA,  NA, 5, NA, NA, 10, 7, NA, NA, 15, 11),
              txt_group = NA_integer_)

# txt_group = helper column for text grouping variable

txt_group_counter <- 1L


for(i in seq_len(nrow(tib))){

  if (!is.na(tib$txt[i]) | !is.na(lag(tib$txt[i]))){

    tib$txt_group[i] <- txt_group_counter
   } 

  if(is.na(tib$txt[i]) | !is.na(lead(tib$txt[i]))){

    txt_group_counter <- txt_group_counter + 1
  }

}


tib1 <- 
  tib %>%
  filter(!is.na(txt_group)) %>% 
  group_by(txt_group) %>% 
  mutate(id_comb = paste(id, collapse = ", "),
         txt = paste(txt, collapse = " "),
         nr = paste(nr, collapse = "")) %>% 
  select(-id) %>% 
  distinct() %>% 
  ungroup() %>% 
  mutate(id = as.numeric(str_extract(id_comb, "^\\d")),
         nr = as.numeric(str_remove_all(nr, "[NA]"))) %>% 
  select(id, id_comb, everything()) %>% 
  bind_rows(tib %>% filter(is.na(txt_group))) %>% 
  arrange(id) %>% 
  select(-txt_group)
4

1 回答 1

1

下面使用使用标准cumsum/diff技巧创建的辅助变量来定义组,然后paste一起定义行。

该代码执行以下操作:

  1. 创建一个逻辑变量eq,判断 的两个连续值var是否相等。由于第一个不能等于之前(在它不存在之前)我用FALSE.
  2. 其中一些值是NA, 将它们替换为FALSE, allNA不同于其他所有值,包括其他值NA
  3. 现在有一个cumsum技巧,在有断点的地方TRUEvar与下一个值不同,请参见上面的第 1 点),就像运行计数一样。这给了组的变化var
  4. 和什么基本相同的技巧适用于is.na(var)cumsum对于创建分组向量非常有用,并且应该在 R 技巧包中占有一席之地。
  5. mutate_at删除值,当组合行时NA它们将被重复。NA NA像这样,它""是组合的空字符串。
  6. 按 分组okeq并与 结合pastetrimws可能不需要,但它不会受到伤害,除非数据集非常大并且代码要针对时间进行优化。
  7. 取消组合并删除创建的临时列;用逗号替换结果中的空格。

这里是:

tib %>% 
  mutate(eq = c(FALSE, var[-length(var)] != var[-1]),
         eq = ifelse(is.na(eq), FALSE, eq),
         eq = cumsum(abs(c(diff(eq), 0))),
         ok = cumsum(abs(c(0, diff(is.na(var)))))) %>%
  mutate_at(vars(var:txt_group), list(function(x) ifelse(is.na(x), "", x))) %>%
  group_by(ok, eq) %>% 
  summarise_all(funs(trimws(paste(., collapse = " ")))) %>%
  ungroup() %>%
  select(-ok, -eq) %>%
  mutate(id = gsub(" ", ",", id),
         var = gsub(" ", ",", var))
## A tibble: 8 x 5
#  id     var   txt          nr    txt_group
#  <chr>  <chr> <chr>        <chr> <chr>    
#1 1      "a"   ""           ""    ""       
#2 2,3    ""    "the cat"    "5"   ""       
#3 4      "b"   ""           ""    ""       
#4 5      "c"   ""           ""    ""       
#5 6      ""    "sat"        "10"  ""       
#6 7      "d"   ""           "7"   ""       
#7 8,9,10 ""    "on the mat" "15"  ""       
#8 11     "e"   ""           "11"  ""  
于 2020-01-30T17:49:35.420 回答