r - 将 NA 替换为子集组内的值
问题描述
对于具有来自多个来源的数据的子组,我需要在 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
解决方案
这里有 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)使用for
带有非标准评估的循环:
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
3) 提取最后一个非 NA 值并执行连接,然后通过引用更新:
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
您也可以使用fifelse
(version >= 1.12.4) 代替fcoalesce
(ie fcoalesce(X, Y) == fifelse(is.na(X), Y, X)
)。
我认为时间将取决于您的实际数据集的特征。
输出:
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)
推荐阅读
- python - 为什么我的正方形(蛇)只在对角线上移动?
- javascript - React.js 参考焦点()
- javascript - 在 Google Scripts 中创建一个简单的计数器来跟踪以前的值
- python - tf.nest.map_structure 与 tf.map_fn 在速度和结果上的差异
- azure - Azure 数据工厂 - 将 YYYYDDMMmmHHss 转换为 DDMMYYYYHHmmSS
- jquery - jQuery DataTable rowGroup 切换不起作用
- r - 将距离矩阵应用于多个数据帧
- amcharts - AmCharts:非常大的数据集的数据分组
- node.js - 如何在mongodb中获取单个数组返回值?
- python - 如何在python中以编程方式分配变量名?