【问题标题】:R: complete sequence column and fill in rowsR:完整的序列列并填充行
【发布时间】:2021-09-15 05:38:27
【问题描述】:

我从一个数据集开始,该数据集有一个数字列(在我的例子中是时间,但采用数字格式)、一个特定的时间戳事件和一个 ID。我希望运行一些代码来扩展数据框以填充数字序列,同时复制事件列(以及任何其他相关列)。我想按 ID 运行它,所以我也不会填补 ID 之间的空白。

这是我开始使用的数据的简化示例。我想分别为每个 ID 填充“值”列的序列,用每个“事件”的第一行中的数据完成每个新行。

 a<-c("162", "164", "169", "171", "174", "188", "191", "198","200")
b<-c("start1","end1","start2", "event", "end2", "start1", "end1", "start2", "end2")
c<-c("A","A","A", "A", "A", "B", "B", "B", "B")

original<-data.table(value = a, event = b, ID = c)

这是对我最终目标的重构:

agoal<-c(seq(from = 162, to = 174), seq(from = 188, to = 200))
bgoal<-c("start1","start1","end1","end1", "end1", "end1", "end1",
     "start2", "start2",  "event", "end2","end2", "end2", 
     "start1", "start1", "start1", "end1", "end1", "end1", "end1", "end1", "end1", "end1",
     "start2", "start2","end2")
cgoal<-c(rep("A",13), rep("B",13))

goal<-data.table(value = agoal, event = bgoal, ID = cgoal)

对不起,如果这不是很清楚!

【问题讨论】:

  • 感谢您的精彩回答!这些效果很好,但我无法将它们应用于最终大小的实际数据集,而不会出现“错误:向量内存已用尽(达到限制?)”

标签: r dataframe time dplyr sequence


【解决方案1】:

使用dplyrtidyr 的另一个选项:

library(dplyr)
library(tidyr)

original %>% 
  split(.$ID) %>% 
  lapply(function(x) data.frame(value = as.character(seq(min(x$value), max(x$value)))) %>% 
           left_join(x, by="value") %>% 
           fill(c("event", "ID"))) %>% 
  do.call(rbind.data.frame, .)

返回

     value  event ID
A.1    162 start1  A
A.2    163 start1  A
A.3    164   end1  A
A.4    165   end1  A
A.5    166   end1  A
A.6    167   end1  A
A.7    168   end1  A
A.8    169 start2  A
A.9    170 start2  A
A.10   171  event  A
A.11   172  event  A
A.12   173  event  A
A.13   174   end2  A
B.1    188 start1  B
B.2    189 start1  B
B.3    190 start1  B
B.4    191   end1  B
B.5    192   end1  B
B.6    193   end1  B
B.7    194   end1  B
B.8    195   end1  B
B.9    196   end1  B
B.10   197   end1  B
B.11   198 start2  B
B.12   199 start2  B
B.13   200   end2  B

或多或少相同,但没有 splitdo.call-part:

original %>% 
  group_by(ID) %>% 
  group_map(function(x, ...) data.frame(value = as.character(seq(min(x$value), max(x$value)))) %>% 
           left_join(original, by="value") %>% 
           fill(c("event", "ID"))) %>% 
  bind_rows()

【讨论】:

    【解决方案2】:

    我们可以使用来自tidyr 包的completefill: 首先使用tpye.convert(as.is=TRUE)将数字分配给value

    library(dplyr)
    library(tidyr)
    
    original %>% 
      type.convert(as.is=TRUE) %>% 
      group_by(ID) %>% 
      complete(value = first(value):max(value)) %>% 
      fill(event) 
    

    输出:

        value  event ID
     1:   162 start1  A
     2:   163 start1  A
     3:   164   end1  A
     4:   165   end1  A
     5:   166   end1  A
     6:   167   end1  A
     7:   168   end1  A
     8:   169 start2  A
     9:   170 start2  A
    10:   171  event  A
    11:   172   end2  A
    12:   173   end2  A
    13:   174   end2  A
    14:   188 start1  B
    15:   189 start1  B
    16:   190 start1  B
    17:   191   end1  B
    18:   192   end1  B
    19:   193   end1  B
    20:   194   end1  B
    21:   195   end1  B
    22:   196   end1  B
    23:   197   end1  B
    24:   198 start2  B
    25:   199 start2  B
    26:   200   end2  B
    

    【讨论】:

      【解决方案3】:

      有两个部分需要处理:a) 如何在value 列中为缺失的数字添加行,b) 如何用之前出现的任何内容填充event。 (b) 很简单(只需使用fill)。 (a) 可以通过使用您想要的所有值创建一个新数据框并与原始数据框连接来完成:

      library(tidyverse)
      
      original %>%
        group_by(ID) %>%
        summarize(a = as.integer(min(value)),
                  b = as.integer(max(value))) %>%
        transpose() %>%
        map(~ data.frame(ID = .x$ID, value = .x$a:.x$b)) %>%
        reduce(bind_rows) %>%
        left_join(original, by = c("value", "ID")) %>%
        group_by(ID) %>%
        fill(event, .direction = "down")
      

      一步一步:

      1. 获取每个组内value 列的最小值和最大值
      2. 使用transpose 将数据框拆分为一个列表(这将提供一个嵌套列表,其中第一级按行号索引,第二级按列名索引)
      3. 使用 map 为每个 ID 创建一个数据帧列表,其中 value 列的所有值都在原始的最小值和最大值之间
      4. 使用reducebind_rows 将所有数据帧混合在一起
      5. 使用valueID 与原始连接;请注意,left_join 将确保所有新的 valueID 组合都存在,即使它们在原始组合中没有任何对应的组合(这将导致任何缺失的 event 值具有 NA,这就是下一步)
      6. 向下填充所有 NA,无论该组中的先前事件是什么

      结果:

         ID value  event
      1   A   162 start1
      2   A   163 start1
      3   A   164   end1
      4   A   165   end1
      5   A   166   end1
      6   A   167   end1
      7   A   168   end1
      8   A   169 start2
      9   A   170 start2
      10  A   171  event
      11  A   172  event
      12  A   173  event
      13  A   174   end2
      14  B   188 start1
      15  B   189 start1
      16  B   190 start1
      17  B   191   end1
      18  B   192   end1
      19  B   193   end1
      20  B   194   end1
      21  B   195   end1
      22  B   196   end1
      23  B   197   end1
      24  B   198 start2
      25  B   199 start2
      26  B   200   end2
      

      请注意,如果您将数值作为original 中的实际数字,则实际上不需要两个as.integer 调用。另外,我认为在 OP 中,您的意思是连续使用 event 三次而不是一次(否则模式被破坏)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-19
        • 1970-01-01
        • 2015-07-08
        • 1970-01-01
        • 1970-01-01
        • 2020-07-17
        • 2018-12-11
        相关资源
        最近更新 更多