如何为重复测量数据创建缺失值?
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
我有一个数据集,并不是每个受试者的观察结果都是在完全相同的时间点观察到的,但我想把它变成一个数据集,每个人的观察结果都是在完全相同的时间点观察到的(这样我可以在 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