我有一个矩阵,其中行可以包含所有列的NA。我想用前一行的非NA值和第K列替换这些NA行。
例如,这个矩阵:
[,1] [,2]
[1,] NA NA
[2,] NA NA
[3,] 1 2
[4,] 2 3
[5,] NA NA
[6,] NA NA
[7,] NA NA
[8,] 6 7
[9,] 7 8
[10,] 8 9
必须转换为此非NA矩阵,我们使用第2列进行替换:
[,1] [,2]
[1,] NA NA
[2,] NA NA
[3,] 1 2
[4,] 2 3
[5,] 3 3
[6,] 3 3
[7,] 3 3
[8,] 6 7
[9,] 7 8
[10,] 8 9
我为此编写了一个函数,但是使用了循环:
# replaces rows which contains all NAs with non-NA values from previous row and K-th column
na.replace <- function(x, k) {
cols <- ncol(x)
for (i in 2:nrow(x)) {
if (sum(is.na(x[i - 1, ])) == 0 && sum(is.na(x[i, ])) == cols) {
x[i, ] <- x[i - 1 , k]
}
}
x
}
似乎这个功能正常,但我想避免这些循环。任何人都可以建议,如何在不使用循环的情况下进行此替换?
更新
agstudy建议它是自己的矢量化非循环解决方案:
na.replace <- function(mat, k){
idx <- which(rowSums(is.na(mat)) == ncol(mat))
mat[idx,] <- mat[ifelse(idx > 1, idx-1, 1), k]
mat
}
但是与我的循环解决方案相比,这个解决方案会返回不同的错误结果。为什么会这样?理论上循环和非循环解决方案是相同的。
答案 0 :(得分:4)
试试这个功能。我们可以在向量中的任何位置替换 NA 。
NA.replace <-function(x) {
i <- cumprod(is.na(x))
x[!!i] <- x[which.min(i)]
if (length(x) > 0L) {
non.na.idx <- which(!is.na(x))
if (is.na(x[1L])) {
non.na.idx <- c(1L, non.na.idx)
}
rep.int(x[non.na.idx], diff(c(non.na.idx, length(x) + 1L)))
}
}
NA.replace(c(NA, 1, 2, NA, NA, 3, NA, NA, 4, NA))
# [1] 1 1 2 2 2 3 3 3 4 4
答案 1 :(得分:2)
这是一个新的矢量化解决方案:
idx <- which(rowSums(is.na(mat)) == ncol(mat))
mat[idx,1:2]= mat[ifelse(idx>1,idx-1,1),2]
X..1. X..2.
[1,] NA NA
[2,] NA NA
[3,] 1 2
[4,] 2 3
[5,] 3 3
[6,] 4 5
[7,] 5 5
[8,] 6 7
[9,] 7 8
[10,] 8 9
您可以将其包装在一个函数中:
function(mat,k){
idx <- which(rowSums(is.na(mat)) == ncol(mat))
mat[idx,] <- mat[ifelse(idx>1,idx-1,1),k]
}
答案 2 :(得分:2)
我在一个循环中使用na.locf
函数,该循环只使用下一列来生成替换值的向量。但是,如果矩阵很大,这可能效率不高。
library(zoo)
m <- cbind(
c(NA, NA, 1, 2, NA, 4, NA, 6, 7, 8),
c(NA, NA, 2, 3, NA, 5, NA, 7, 8, 9)
)
m[, ncol(m)] <- na.locf(m[, ncol(m)], na.rm=FALSE)
for (i in seq(ncol(m)-1, 1)) {
replacement_values = na.locf(m[, i+1], na.rm=FALSE)
m[is.na(m[, i]), i] <- replacement_values[is.na(m[, i])]
}
答案 3 :(得分:0)
最后我意识到了自己的矢量化版本。它返回预期的输出:
na.replace <- function(x, k) {
isNA <- is.na(x[, k])
x[isNA, ] <- na.locf(x[, k], na.rm = F)[isNA]
x
}
<强>更新强>
更好的解决方案,没有任何软件包
na.lomf <- function(x) {
if (length(x) > 0L) {
non.na.idx <- which(!is.na(x))
if (is.na(x[1L])) {
non.na.idx <- c(1L, non.na.idx)
}
rep.int(x[non.na.idx], diff(c(non.na.idx, length(x) + 1L)))
}
}
na.lomf(c(NA, 1, 2, NA, NA, 3, NA, NA, 4, NA))
# [1] NA 1 2 2 2 3 3 3 4 4