R:用两个最连续值的平均值替换 NA

Ser*_*nte 1 replace r mean na

一个数据框:

x <- c(3,4,8,10,NA,NA,NA,8,10,10,NA,22)
y <- c(1,6,3,5,NA,44,23,NA,NA,5,34,33)
df <- data.frame(x,y)

x   y
<dbl>   <dbl>
3   1           
4   6           
8   3           
10  5           
NA  NA          
NA  44          
NA  23          
8   NA          
10  NA          
10  5           
NA  34          
22  33  
Run Code Online (Sandbox Code Playgroud)

我想用两个最连续值的平均值替换 NA 值。例如df[5,2]NA但我们可以用 5 和 44 的平均值替换它:

df[5,2] <- (df[4,2]+df[6,2])/2

df[5,2]
[1] 24.5
Run Code Online (Sandbox Code Playgroud)

但是,如果连续值也是 ,则无法完成此操作NA。更换df[6,1]用的均df[5,1]df[7,1],因为他们也NA不起作用。

我想要完成的是确保我用来计算平均值的值是两个最连续的值,而不是NA. 我创建了一个 for 循环来创建我们找到的索引的数据框NAs。然后,我创建了代表 旁边的索引的变量,NA并进行了评估它们是否为 的测试NA。如果TRUE是 NA,则索引会根据相对于NA索引的位置而增加或减少:

x <- as.data.frame(which(is.na(df), arr.ind = TRUE))
str(x)

  'data.frame': 7 obs. of  2 variables:
   $ row: int  5 6 7 11 5 8 9
   $ col: int  1 1 1 1 2 2 2
Run Code Online (Sandbox Code Playgroud)

您将看到一个数据框,其中包含NAs数据集中位置的行和列值。现在我尝试覆盖它们:

for (i in 1:dim(x)[1]) {

    row <- x[i,1]          # First for loop assigns row and column values using the location of NA
    col <- x[i,2]

    b <- row - 1           # Create a list of the indices that precede the NA
    a <- row + 1           # Create a list of the indices that go after the NA

    ifelse(is.na(df[b[i],col]), b[i]-1, b[i])    # If the value in the list is also an NA, keep looking
    ifelse(is.na(df[a[i],col]), a[i]+1, a[i])

    df[row,col] <- (df[b,col]+df[a,col])/2       # Replace the NA with the mean of values where we could 
                                                 # find integers

}
Run Code Online (Sandbox Code Playgroud)

唉,我无法通过所有的 NA。我还没有想出更好的解决方案,因此转向更好的想法。非常感谢!

y <- as.data.frame(which(is.na(df), arr.ind = TRUE))
str(y)

'data.frame':   5 obs. of  2 variables:
 $ row: int  5 6 7 8 9
 $ col: int  1 1 1 2 2
Run Code Online (Sandbox Code Playgroud)

duc*_*ayr 5

我们可以使用这个zoo::na.locf()函数:

x <- c(3,4,8,10,NA,NA,NA,8,10,10,NA,22)
y <- c(1,6,3,5,NA,44,23,NA,NA,5,34,33)
df <- data.frame(x,y)

contiguous_mean <- function(vec) {
    return( (zoo::na.locf(vec) + zoo::na.locf(vec, fromLast = TRUE)) / 2 )
}

apply(df, 2, contiguous_mean)

#        x    y
#  [1,]  3  1.0
#  [2,]  4  6.0
#  [3,]  8  3.0
#  [4,] 10  5.0
#  [5,]  9 24.5
#  [6,]  9 44.0
#  [7,]  9 23.0
#  [8,]  8 14.0
#  [9,] 10 14.0
# [10,] 10  5.0
# [11,] 16 34.0
# [12,] 22 33.0
Run Code Online (Sandbox Code Playgroud)

这里,“LOCF”代表AST ö bservation Ç arried ˚F orward,它取代NA与最后观测值的值; 对于fromLast参数,您可以使用最近的先前观察,或最近的后续观察。我们想要上一个前一个观测值和下一个后续观测值的平均值,因此我们只需将结果的总和除以fromLastasTRUEFALSE

更新:开头或结尾NA小号

G. Grothendieck 提出了使用na.locf0()而不是na.locf()使用na.rm = FALSE前者的默认值的极好建议。当初始值或最后一个值不是 时 NA,这两种方法是等效的,但是当您的列以NAs开头或结尾时,我们需要na.locf0(). 这是一个演示:

z <- c(NA, 1, 2, NA, 3)
contiguous_mean <- function(vec) {
    return( (zoo::na.locf(vec) + zoo::na.locf(vec, fromLast = TRUE)) / 2 )
}
contiguous_mean2 <- function(vec) {
    return( (zoo::na.locf0(vec) + zoo::na.locf0(vec, fromLast = TRUE)) / 2 )
}
## When no leading or trailing NAs, they are equivalent:
all.equal(apply(df, 2, contiguous_mean), apply(df, 2, contiguous_mean2))
# [1] TRUE
## However, when there *are* leading or trailing NAs, the first approach
## causes bad recycling:
contiguous_mean2(z) ## New version
# [1]  NA 1.0 2.0 2.5 3.0
contiguous_mean(z)  ## Old version
# [1] 1.0 1.5 2.0 3.0 2.0
# Warning message:
# In zoo::na.locf(vec) + zoo::na.locf(vec, fromLast = TRUE) :
#   longer object length is not a multiple of shorter object length
Run Code Online (Sandbox Code Playgroud)