根据是否存在不需要的变量组合,将观测值替换为 NA



起始数据是一个带有缺失值的数字矩阵,以及一个包含我永远不想一起存在的变量组合的 2 列数据帧。目标是根据不需要的变量组合的存在,将数字矩阵中的单元格替换为 NA。删除也应按删除最少数量的变量以避免任何"错误"组合的顺序进行。

一个例子应该有助于澄清。我从以下内容开始:

set.seed(1221)
dat <- matrix(rep(1, 16), ncol=4)
colnames(dat) <- c("V1", "V2", "V3", "V4")
dat[sample(length(dat),3)] <- NA
bad_combos <- data.frame(Var1 = c("V1", "V3"), Var2 = c("V2", "V4"))

这里的"dat"是我的矩阵,"bad_combos"给出了我不想同时出现的变量名称对。因此,在这种情况下,变量"V1"和"V2"不应该同时是非NA,而"V3"和"V4"不应该都是非NA。

我想出了一个糟糕的解决方案,无法针对我的真实数据集进行扩展(也存在内存问题(。它使用 for 循环遍历每一行,使用内部连接来提出有问题的重叠行,然后相应地开始用 NA 替换单元格。我使用 table(( 和 which.max(( 来确保我首先删除最常见的问题变量以尽量减少删除的内容(如果没有区别,就像这里的情况一样,那么它只是删除第一种情况很好(。

for(i in 1:dim(dat)[1]) {
resp.cols <- colnames(dat)[which(!is.na(dat[i,]))]
eg <- expand.grid(resp.cols, resp.cols)
vars <- suppressWarnings(dplyr::inner_join(bad_combos[, c("Var1", "Var2")], eg, by=c("Var1", "Var2")) )
dat.sort <- t(apply(vars, 1, sort))
vars <- vars[!duplicated(dat.sort),]
if(dim(vars)[1] != 0) {
done <- FALSE
while(done == FALSE){
remove <- names(which.max(table(c(vars$Var1, vars$Var2))))
dat[i, remove] <- NA #make this one appear missing
print("got one")
vars <- vars[-which(vars$Var1 == remove | vars$Var2 == remove),]
if(dim(vars)[1] == 0) done <- TRUE
} 
} 
}

目前,此函数实现了预期的结果,即"dat"将正确的单元格替换为NA,因此不存在任何不良组合。但它的效率非常低,这是有问题的,因为我需要它在具有 60 列和 20,000 行的矩阵上工作。我觉得一定有一个优雅的解决方案吗?

因此,如果你的糟糕连击总是成对发生,那么你一次只看一对,这就像你的 for 循环一样。对于一对,您只能替换为 NA,即在对关联列中没有 NA 的行:

set.seed(1221)
dat <- matrix(rep(1, 16), ncol=4)
colnames(dat) <- c("V1", "V2", "V3", "V4")
dat[sample(length(dat),3)] <- NA
bad_combos <- data.frame(Var1 = c("V1", "V3"), Var2 = c("V2", "V4"),stringsAsFactors=FALSE)
for(i in 1:nrow(bad_combos)){
#find the columns that match this combination
sel = which(colnames(dat) %in% bad_combos[i,])
# identify rows we can change, looking only at the relevant columns
tochange = rowSums(is.na(dat[,sel]))==0
dat[tochange,sel[1]] = NA
}

如果需要删除最小列数:

bad_combos <- cbind(Var1 = c("V1", "V2", "V3"),Var2=c("V4", "V4", "V4"))
lvl = names(sort(table(bad_combos),decreasing=TRUE))
sorted_combos = t(apply(bad_combos,1,function(i)sort(factor(i,levels=lvl))))

并sorted_combos重复上述操作。

最新更新