R 将NA替换为子集的组内值
对于具有多个源数据的子组,我需要在ID和时间点内替换数据帧的所有列中缺少的值。如果不太复杂,最好对源B中的数据进行优先级排序(例如,在下面数据中变量Y的id为2的情况下) 使用下面的代码,它目前一次只能处理一列(没有优先级),但由于它是一个包含数百万行的大型数据帧,因此需要进一步自动化。另外,如果可能的话,我希望将其保存在data.table框架内。有什么建议吗R 将NA替换为子集的组内值,r,performance,loops,data.table,subset,R,Performance,Loops,Data.table,Subset,对于具有多个源数据的子组,我需要在ID和时间点内替换数据帧的所有列中缺少的值。如果不太复杂,最好对源B中的数据进行优先级排序(例如,在下面数据中变量Y的id为2的情况下) 使用下面的代码,它目前一次只能处理一列(没有优先级),但由于它是一个包含数百万行的大型数据帧,因此需要进一步自动化。另外,如果可能的话,我希望将其保存在data.table框架内。有什么建议吗 # Data id time X Y Source 1 2005 67 NA A 1 2005 NA 1.1
# Data
id time X Y Source
1 2005 67 NA A
1 2005 NA 1.1 B
1 2005 NA 1.1 B
2 2003 85 NA B
2 2003 NA 0.4 A
2 2003 85 0.5 B
# Desired output
id time X Y Source
1 2005 67 1.1 A
1 2005 67 1.1 B
1 2005 67 1.1 B
2 2003 85 0.5 B
2 2003 85 0.4 A
2 2003 85 0.5 B
# Find duplicates
dup <- (duplicated(dat[,c('id','time')])|duplicated(dat[,c('id','time')], fromLast=TRUE))
# Replace NA in column X
library(data.table)
dat[dup & is.na(X), X := dat[!is.na(X)][.SD, on=.(id,time), mult="last", X]]
### Solution based on locf and an internal data.table loop (still slower than tidyverse)
library(data.table)
library(zoo)
cols <- colnames(dat)[c(-1,-2)]
dat <- dat[order(id,time,Source)] # this combined with na.locf0(fromLast=T) takes care of the priority.
dup <- (duplicated(dat[,c('id','time')])|duplicated(dat[,c('id','time')], fromLast=TRUE))
t1 <- Sys.time()
dat=rbind(
dat[!dup],
dat[dup, lapply(.SD, na.locf0,fromLast = TRUE), by=c('id','time'), .SDcols = cols][
,lapply(.SD, na.locf0), by=c('id','time'), .SDcols = cols]
)
t2 <- Sys.time()
t2-t1
#数据
id时间X Y源
1 2005 67 NA A
1 2005 NA 1.1 B
1 2005 NA 1.1 B
2003年2月85日不适用
2003NA 0.4A
2 2003 85 0.5 B
#期望输出
id时间X Y源
1 2005 67 1.1 A
1 2005 67 1.1 B
1 2005 67 1.1 B
2 2003 85 0.5 B
2 2003 85 0.4 A
2 2003 85 0.5 B
#查找重复项
dup库(tidyverse)
库(数据表)
数据%
填充(时间,X,Y)%>%
填充(时间,X,Y,.direction=“向上”)
数据%
分组依据(id)%>%
填充(时间,X,Y)%>%
填充(时间,X,Y,.direction=“向上”)
我不确定您是指来源“B”始终是首选的,还是仅当样品来源也是“B”时才首选(因此,如果该样品的来源是“A”,首选来源将是“A”)。这段代码解决了后一种场景的问题。
它需要tidyverse。这里有3个选项:
1) 将for
循环与get
一起使用:
for (x in updcols) {
DT0[dup & is.na(get(x)), (x) := DT0[!is.na(get(x))][
.SD, on=.(id,time), mult="last", get(x)]]
}
DT0
2) 对具有非标准评估的
循环使用:
nsef <- function(dat, coln) {
eval(substitute(
dat[dup & is.na(V), V := dat[!is.na(V)][.SD, on=.(id,time), mult="last", V]],
list(V=as.name(coln))
))
}
for (x in updcols) {
nsef(DT1, x)
}
DT1
数据:
library(data.table)#data.table_1.12.6
DT我有点困惑,您能显示所需的输出吗?很抱歉,现在添加。请包括所有库
行,因为这似乎不是数据。表
。OP请求:如果可能的话,我想把它保存在data.table框架内。谢谢!我一直在使用类似的解决方案,但随着数据集的扩展,速度变得太慢了。其余的数据管理也在data.table框架中进行,因此将其全部带到那里将是非常好的。我认为解决方案与其中的.SDcols和(cols)有关,但尚未完全解决。感谢您的努力!不幸的是,这些解决方案对于我的数据集(其中包含混合的变量类型)来说太慢了,但它们帮助我找到了上面的解决方案。
nsef <- function(dat, coln) {
eval(substitute(
dat[dup & is.na(V), V := dat[!is.na(V)][.SD, on=.(id,time), mult="last", V]],
list(V=as.name(coln))
))
}
for (x in updcols) {
nsef(DT1, x)
}
DT1
lu <- DT2[, lapply(.SD, function(x) last(x[!is.na(x)])), bycols, .SDcols=updcols]
DT2[(dup), (updcols) :=
lu[.SD, on=bycols, Map(function(x, y) fcoalesce(x, y),
mget(paste0("i.", updcols)), mget(updcols))]
]
DT2
id time X Y Source
1: 1 2005 67 1.1 A
2: 1 2005 67 1.1 B
3: 1 2005 67 1.1 B
4: 2 2003 85 0.5 B
5: 2 2003 85 0.4 A
6: 2 2003 85 0.5 B
library(data.table) #data.table_1.12.6
DT <- fread("id time X Y Source
1 2005 67 NA A
1 2005 NA 1.1 B
1 2005 NA 1.1 B
2 2003 85 NA B
2 2003 NA 0.4 A
2 2003 85 0.5 B")
DT0 <- copy(DT)
DT1 <- copy(DT)
DT2 <- copy(DT)
bycols <- c('id','time')
updcols <- c("X", "Y")
dup <- duplicated(DT, by=bycols) | duplicated(DT, by=bycols, fromLast=TRUE)