R 为缺少的时间步长添加行的最快方法?

R 为缺少的时间步长添加行的最快方法?,r,dataframe,plyr,data.table,R,Dataframe,Plyr,Data.table,我的数据集中有一列,其中时间段(time)是从a到b的整数。有时,任何给定的组都可能缺少时间段。我想在这些行中填入NA。以下是1000组中1组的示例数据 如你所见,时间3不见了。通常可能会丢失一个或多个。我可以自己解决这个问题,但恐怕我不会用最有效的方法来解决。我的方法是创建一个函数: 生成从min(time)到max(time) 然后执行setdiff以获取缺少的Time值 将该向量转换为data.frame 提取唯一标识符变量(Id和上面未列出的其他变量),并将其添加到此data.frame

我的数据集中有一列,其中时间段(
time
)是从a到b的整数。有时,任何给定的组都可能缺少时间段。我想在这些行中填入
NA
。以下是1000组中1组的示例数据

如你所见,时间3不见了。通常可能会丢失一个或多个。我可以自己解决这个问题,但恐怕我不会用最有效的方法来解决。我的方法是创建一个函数:

生成从
min(time)
max(time)

然后执行
setdiff
以获取缺少的
Time

将该向量转换为
data.frame

提取唯一标识符变量(
Id
和上面未列出的其他变量),并将其添加到此data.frame

将两者合并

从函数返回

因此,整个过程将按如下方式执行:

   # Split the data into individual data.frames by Id.
    temp_list <- dlply(original_data, .(Id)) 
    # pad each data.frame
    tlist2 <- llply(temp_list, my_pad_function)
    # collapse the list back to a data.frame
    filled_in_data <- ldply(tlist2)
#按Id将数据拆分为单个数据帧。

temp_list我的一般方法是使用
frektable请参阅Matthew Dowle的答案(到目前为止,希望在上面)

下面是一些使用
data.table
包的东西,当存在多个ID变量时,它可能会有所帮助。它也可能比
合并
更快,这取决于您想要结果的方式。我对基准测试和/或改进建议感兴趣

首先,使用两个ID变量创建一些要求更高的数据

library(data.table)

set.seed(1)

mydf3<-data.frame(Id=sample(1:100,10000,replace=TRUE),
  Value=rnorm(10000))
mydf3<-mydf3[order(mydf3$Id),]

mydf3$Time<-unlist(by(mydf3,mydf3$Id,
  function(x)sample(1:(nrow(x)+3),nrow(x)),simplify=TRUE))

mydf3$Id2<-sample(1:2,nrow(mydf3),replace=TRUE)
库(data.table)
种子(1)

mydf3跟进Ben Barnes的评论,从他的mydf3
开始:

DT = as.data.table(mydf3)
setkey(DT,Id,Time)
DT[CJ(unique(Id),seq(min(Time),max(Time)))]
      Id Time        Value Id2
 [1,]  1    1 -0.262482283   2
 [2,]  1    2 -1.423935165   2
 [3,]  1    3  0.500523295   1
 [4,]  1    4 -1.912687398   1
 [5,]  1    5 -1.459766444   2
 [6,]  1    6 -0.691736451   1
 [7,]  1    7           NA  NA
 [8,]  1    8  0.001041489   2
 [9,]  1    9  0.495820559   2
[10,]  1   10 -0.673167744   1
First 10 rows of 12800 printed. 

setkey(DT,Id,Id2,Time)
DT[CJ(unique(Id),unique(Id2),seq(min(Time),max(Time)))]
      Id Id2 Time      Value
 [1,]  1   1    1         NA
 [2,]  1   1    2         NA
 [3,]  1   1    3  0.5005233
 [4,]  1   1    4 -1.9126874
 [5,]  1   1    5         NA
 [6,]  1   1    6 -0.6917365
 [7,]  1   1    7         NA
 [8,]  1   1    8         NA
 [9,]  1   1    9         NA
[10,]  1   1   10 -0.6731677
First 10 rows of 25600 printed. 
CJ
表示交叉连接,请参见
?CJ
。使用
NA
s填充是因为默认情况下
nomatch
NA
。改为将
nomatch
设置为
0
,以删除不匹配项。如果不需要使用
NA
s填充当前行,只需添加
roll=TRUE
。这可能比先用
NA
s填充,然后再填充
NA
s更有效。请参阅
数据表中的
滚动
说明

setkey(DT,Id,Time)
DT[CJ(unique(Id),seq(min(Time),max(Time))),roll=TRUE]
      Id Time        Value Id2
 [1,]  1    1 -0.262482283   2
 [2,]  1    2 -1.423935165   2
 [3,]  1    3  0.500523295   1
 [4,]  1    4 -1.912687398   1
 [5,]  1    5 -1.459766444   2
 [6,]  1    6 -0.691736451   1
 [7,]  1    7 -0.691736451   1
 [8,]  1    8  0.001041489   2
 [9,]  1    9  0.495820559   2
[10,]  1   10 -0.673167744   1
First 10 rows of 12800 printed. 

setkey(DT,Id,Id2,Time)
DT[CJ(unique(Id),unique(Id2),seq(min(Time),max(Time))),roll=TRUE]
      Id Id2 Time      Value
 [1,]  1   1    1         NA
 [2,]  1   1    2         NA
 [3,]  1   1    3  0.5005233
 [4,]  1   1    4 -1.9126874
 [5,]  1   1    5 -1.9126874
 [6,]  1   1    6 -0.6917365
 [7,]  1   1    7 -0.6917365
 [8,]  1   1    8 -0.6917365
 [9,]  1   1    9 -0.6917365
[10,]  1   1   10 -0.6731677
First 10 rows of 25600 printed. 

您可以在
上使用
,而不是设置键
CJ
还接受一个
唯一的
参数。有两个“Id”的小示例:

d <- data.table(Id = rep(1:2, 4:3), Time = c(1, 2, 4, 5, 2, 3, 4), val = 1:7)

d[CJ(Id, Time = seq(min(Time), max(Time)), unique = TRUE), on = .(Id, Time)]
#     Id Time val
# 1:   1    1   1
# 2:   1    2   2
# 3:   1    3  NA
# 4:   1    4   3
# 5:   1    5   4
# 6:   2    1  NA
# 7:   2    2   5
# 8:   2    3   6
# 9:   2    4   7
# 10:  2    5  NA

d您可以使用
tidyr
进行此操作

用于填充
时间
的行,默认情况下,值用
NA
填充

创建数据 我扩展了示例数据,以表明它适用于多个
Id
s,甚至在
Id
时间的完整范围也不存在

库(dplyr)
图书馆(tidyr)
df#A tibble:7 x 3
#>Id时间值
#>     
#> 1     1     1  0.56
#> 2     1     2 -0.72
#> 3     1     4  1.24
#> 4     1     5  0.68
#> 5     2     2  1.46
#> 6     2     3  0.74
#> 7     2     5  0.99
填写缺少的行
df%>%完成(嵌套(Id),时间=顺序(最小(时间),最大(时间),1L))
#>#tibble:10 x 3
#>Id时间值
#>      
#> 1      1     1  0.56
#> 2      1     2 -0.72
#>313NA
#> 4      1     4  1.24
#> 5      1     5  0.68
#>6 2 1 NA
#> 7      2     2  1.46
#> 8      2     3  0.74
#>924NA
#> 10     2     5  0.99

我基本上会按照你描述的做,只使用
展开.grid
然后
合并
all=TRUE
。确实,不确定是否需要首先按Id进行拆分。这是一个更复杂的问题,有许多Id变量。我只需要添加
Time
并将
Value
设置为
NA
并填充其余部分。因此,它变成了
data\u to\u merge我现在已经让它工作了,但仍然可以使用一个通用的解决方案,因为这将在一个包中,我不知道用户可以提交什么作为原始数据。对于未分组的数据,请参阅.Right包中的几个不错的答案,但太复杂了。您是否不知何故错过了专门用于此的
roll=TRUE
?保持表中的数据不规则,然后将规则的时间序列加入到表中。请参阅“data.table简介”vignette的第3节,以及使用
roll=TRUE
?data.table
中的示例。这是软件包的主要功能之一。@MatthewDowle,您比我更了解自己的功能,欢迎您提出任何改进建议。由于OP希望为每个缺少的
time
“pad”非ID和非时间变量
NA
,我认为使用
roll=TRUE
将是错误的方法,因为这将“pad”上一个值,对吗?函数中的大多数复杂性似乎都与考虑多个ID变量有关,而不是与连接部分有关,这在
data.table
中是可以很好地实现的;它如何帮助我获得NA?@Siralen See e.g.@MattDowle可能会编辑您非常好的答案,以包括更新的功能,例如作为
设置键
的替代,以及在
CJ
中使用
唯一
参数。Cheers@MattDowle我做了编辑。希望看起来没问题。干杯。@Henrik看起来很棒。谢谢。我发现这个特殊的解决方案最容易回答上述问题,尤其是在使用tidyverse进行数据操作时。
DT = as.data.table(mydf3)
setkey(DT,Id,Time)
DT[CJ(unique(Id),seq(min(Time),max(Time)))]
      Id Time        Value Id2
 [1,]  1    1 -0.262482283   2
 [2,]  1    2 -1.423935165   2
 [3,]  1    3  0.500523295   1
 [4,]  1    4 -1.912687398   1
 [5,]  1    5 -1.459766444   2
 [6,]  1    6 -0.691736451   1
 [7,]  1    7           NA  NA
 [8,]  1    8  0.001041489   2
 [9,]  1    9  0.495820559   2
[10,]  1   10 -0.673167744   1
First 10 rows of 12800 printed. 

setkey(DT,Id,Id2,Time)
DT[CJ(unique(Id),unique(Id2),seq(min(Time),max(Time)))]
      Id Id2 Time      Value
 [1,]  1   1    1         NA
 [2,]  1   1    2         NA
 [3,]  1   1    3  0.5005233
 [4,]  1   1    4 -1.9126874
 [5,]  1   1    5         NA
 [6,]  1   1    6 -0.6917365
 [7,]  1   1    7         NA
 [8,]  1   1    8         NA
 [9,]  1   1    9         NA
[10,]  1   1   10 -0.6731677
First 10 rows of 25600 printed. 
setkey(DT,Id,Time)
DT[CJ(unique(Id),seq(min(Time),max(Time))),roll=TRUE]
      Id Time        Value Id2
 [1,]  1    1 -0.262482283   2
 [2,]  1    2 -1.423935165   2
 [3,]  1    3  0.500523295   1
 [4,]  1    4 -1.912687398   1
 [5,]  1    5 -1.459766444   2
 [6,]  1    6 -0.691736451   1
 [7,]  1    7 -0.691736451   1
 [8,]  1    8  0.001041489   2
 [9,]  1    9  0.495820559   2
[10,]  1   10 -0.673167744   1
First 10 rows of 12800 printed. 

setkey(DT,Id,Id2,Time)
DT[CJ(unique(Id),unique(Id2),seq(min(Time),max(Time))),roll=TRUE]
      Id Id2 Time      Value
 [1,]  1   1    1         NA
 [2,]  1   1    2         NA
 [3,]  1   1    3  0.5005233
 [4,]  1   1    4 -1.9126874
 [5,]  1   1    5 -1.9126874
 [6,]  1   1    6 -0.6917365
 [7,]  1   1    7 -0.6917365
 [8,]  1   1    8 -0.6917365
 [9,]  1   1    9 -0.6917365
[10,]  1   1   10 -0.6731677
First 10 rows of 25600 printed. 
d <- data.table(Id = rep(1:2, 4:3), Time = c(1, 2, 4, 5, 2, 3, 4), val = 1:7)

d[CJ(Id, Time = seq(min(Time), max(Time)), unique = TRUE), on = .(Id, Time)]
#     Id Time val
# 1:   1    1   1
# 2:   1    2   2
# 3:   1    3  NA
# 4:   1    4   3
# 5:   1    5   4
# 6:   2    1  NA
# 7:   2    2   5
# 8:   2    3   6
# 9:   2    4   7
# 10:  2    5  NA