R 将NA替换为子集的组内值

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

对于具有多个源数据的子组,我需要在ID和时间点内替换数据帧的所有列中缺少的值。如果不太复杂,最好对源B中的数据进行优先级排序(例如,在下面数据中变量Y的id为2的情况下)

使用下面的代码,它目前一次只能处理一列(没有优先级),但由于它是一个包含数百万行的大型数据帧,因此需要进一步自动化。另外,如果可能的话,我希望将其保存在data.table框架内。有什么建议吗

# 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)