我有一个数据集,我在某个人身上观察变量而不是其他人.对于我观察变量的那些人,我只观察了一次.但是,每个人的观察数量以及观察值的位置会有所不同.
如果存在非NA值,我想用非NA值填充给定个体的所有NA值.否则,NA应该保持NA.
这是一个示例数据集:
#data.frame of 100 individuals with 10 observations each
data <- data.frame(group = rep(1:100,each=10),value = NA)
#first 50 individuals get a value at the fifth observation, others don't have value
data$value[seq(5,500,10)] <- rnorm(50)
Run Code Online (Sandbox Code Playgroud)
到目前为止这么好,不是一个大问题.从另一个线程中获取,我们可以使用dplyr和执行以下操作tidyr:
data <- data %>%
group_by(group) %>% #by group
fill(value) %>% #default direction down
fill(value, .direction = "up") #also fill NAs upwards
Run Code Online (Sandbox Code Playgroud)
这完全解决了这个问题.但是,我必须为大约80十年代做这件事.观察,需要数小时.有更快的方法吗?我认为data.table可能是一个很好的候选人.
如果可以调整方法以仅填充出现在值之前的NA,那也将是很好的.
谢谢!
你可以使用一个非常简单的方法,data.table和dplyr - 我相信 - 会非常快速和高效:
在data.table中:
library(data.table)
setDT(data)
data[, value := value[!is.na(value)][1L], by = group]
Run Code Online (Sandbox Code Playgroud)
或者dplyr:
library(dplyr)
data <- data %>%
group_by(group) %>%
mutate(value = value[!is.na(value)][1L])
Run Code Online (Sandbox Code Playgroud)
关键是你每组的非NA值恰好是o或1次.因此,您不需要最后观察结转的逻辑.只需取第一个非NA值(如果存在).
这是我使用的代码:你的代码 vs akrun vs 我的代码。有时动物园不是最快的过程,但它是最干净的。无论如何,你可以测试一下。
更新:它已经用更多数据(100.000)进行了测试,到目前为止,进程 03(子集和合并)获胜。
最后的 UPDATE 函数与 rbenchmark 的比较:
library(dplyr)
library(tidyr)
library(base)
library(data.table)
library(zoo)
library(rbenchmark)
#data.frame of 100 individuals with 10 observations each
data <- data.frame(group = rep(1:10000,each=10),value = NA)
data$value[seq(5,5000,10)] <- rnorm(50) #first 50 individuals get a value at the fifth observation, others don't have value
#Process01
P01 <- function (data){
data01 <- data %>%
group_by(group) %>% #by group
fill(value) %>% #default direction down
fill(value, .direction = "up") #also fill NAs upwards
return(data01)
}
#Process02
P02 <- function (data){
data02 <- setDT(data)[, value := na.locf(na.locf(value, na.rm = FALSE),
fromLast = TRUE), group]
return(data02)
}
#Process03
P03 <- function (data){
dataU <- subset(unique(data), value!='NA') #keep row number
dataM <- merge(data, dataU, by = "group", all=T) #merge tables
data03 <- data.frame(group=dataM$group, value = dataM$value.y) #idem shape of data
return(data03)
}
benchmark("P01_dplyr" = {data01 <- P01(data)},
"P02_zoo" = {data02 <- P02(data)},
"P03_data.table" = {data03 <- P03(data)},
replications = 10,
columns = c("test", "replications", "elapsed")
)
Run Code Online (Sandbox Code Playgroud)
数据 = 10.000、10 次重复和 I5 7400 的结果:
test replications elapsed
1 P01_dplyr 10 257.78
2 P02_zoo 10 10.35
3 P03_data.table 10 0.09
Run Code Online (Sandbox Code Playgroud)