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