如何为重复测量数据创建缺失值?

How to create missing value for repeated measurement data?

我有一个数据集,并不是每个受试者的观察结果都是在完全相同的时间点观察到的,但我想把它变成一个数据集,每个人的观察结果都是在完全相同的时间点观察到的(这样我可以在 SAS proc traj 中使用它)。

例如,假设我有数据集"m":

id   <- c(1,1,1,1,2,2,3,3,3)
age  <- c(2,3,4,5,3,6,2,5,8)
IQ   <- c(3,4,5,4,6,5,3,8,10)
m    <- data.frame(id,age,IQ)
> m
  id age IQ
1  1   2  3
2  1   3  4
3  1   4  5
4  1   5  4
5  2   3  6
6  2   6  5
7  3   2  3
8  3   5  8
9  3   8 10
> unique(age)
[1] 2 3 4 5 6 8

我想把m变成m2。但我只能手动做到这一点。

id2   <- c(1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3)
age2  <- c(2,3,4,5,6,8,2,3,4,5,6,8,2,3,4,5,6,8) 
IQ2   <- c(3,4,5,4,NA,NA,6,5,NA,NA,NA,NA,3,8,10,NA,NA,NA) 
m2    <- data.frame(id2,age2,IQ2)    
m2
> m2
   id2 age2 IQ2
1    1    2   3
2    1    3   4
3    1    4   5
4    1    5   4
5    1    6  NA
6    1    8  NA
7    2    2   6
8    2    3   5
9    2    4  NA
10   2    5  NA
11   2    6  NA
12   2    8  NA
13   3    2   3
14   3    3   8
15   3    4  10
16   3    5  NA
17   3    6  NA
18   3    8  NA

有谁知道更聪明的方法吗?

使用 tidyr,这是一个单一的班轮。您使用 complete 函数,该函数使用传递给它的列的每个组合创建行,并用 NA:

填充其余行
library(tidyr)
complete(m, id, age)

Source: local data frame [18 x 3]

      id   age    IQ
   (dbl) (dbl) (dbl)
1      1     2     3
2      1     3     4
3      1     4     5
4      1     5     4
5      1     6    NA
6      1     8    NA
7      2     2    NA
8      2     3     6
9      2     4    NA
10     2     5    NA
11     2     6     5
12     2     8    NA
13     3     2     3
14     3     3    NA
15     3     4    NA
16     3     5     8
17     3     6    NA
18     3     8    10

我们可以使用 data.table 来做到这一点。我们将 data.frame 转换为 data.table (setDT(m)),设置键列 (setkey) 并使用 unique 元素的交叉连接进行连接 'id' 和 'age'

library(data.table)
setkey(setDT(m), id, age)[CJ(unique(id), unique(age))]
#    id age IQ
# 1:  1   2  3
# 2:  1   3  4
# 3:  1   4  5
# 4:  1   5  4
# 5:  1   6 NA
# 6:  1   8 NA
# 7:  2   2 NA
# 8:  2   3  6
# 9:  2   4 NA
#10:  2   5 NA
#11:  2   6  5
#12:  2   8 NA
#13:  3   2  3
#14:  3   3 NA
#15:  3   4 NA
#16:  3   5  8
#17:  3   6 NA
#18:  3   8 10

在开发版本中,即 v1.9.5,我们可以在 CJ 中使用 unique=TRUE(来自@Frank 的评论)

setDT(m, key=c('id', 'age'))[CJ(id, age, unique=TRUE)]

基准

set.seed(24)
m1 <- data.frame(id=rep(1:10000, each=10), age=sample(2:400, 10000*10, 
         replace=TRUE), IQ=rnorm(10000*10))
system.time(res1 <- complete(m1, id, age))
# user  system elapsed 
#18.888   0.000  16.258 


system.time({ DT <- as.data.table(m1)
         res2 <- setkey(DT, id, age)[CJ(unique(id), unique(age))]})
#  user  system elapsed 
#  0.000   0.000   0.279 



library(microbenchmark)
jeremy <- function() complete(m1, id, age)
akrun <- function() {DT <- as.data.table(m1)
   setkey(DT, id, age)[CJ(unique(id), unique(age))]}

microbenchmark(jeremy(), akrun(), times=20L, unit='relative')
#Unit: relative
#   expr      min       lq   mean   median       uq      max neval cld
#jeremy() 24.95042 30.84234 17.138 23.09175 12.16891 8.305394    20   b
# akrun()  1.00000  1.00000  1.000  1.00000  1.00000 1.000000    20  a