R:用两个最连续值的平均值替换 NA
R: replace NAs with mean of two most contiguous values
一个数据框:
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
我想用两个最连续值的平均值替换 NA 值。例如 df[5,2]
是 NA
但我们可以将其替换为 5 和 44 的平均值:
df[5,2] <- (df[4,2]+df[6,2])/2
df[5,2]
[1] 24.5
但是,如果连续值也是NA
,则无法完成此操作。用 df[5,1]
和 df[7,1]
之间的平均值替换 df[6,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
您将看到一个数据框,其中包含数据集中 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
}
唉,我无法通过所有的 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
我们可以为此使用 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
这里,"locf"代表last observation carried forward,用最后一个观测值替换NA
值;使用 fromLast
参数,您可以使用最近的 previous 观察,或最近的 subsequent 观察。我们想要上一个观察值和下一个观察值的平均值,所以我们只需将 fromLast
结果之和除以二,即 TRUE
和 FALSE
.
更新:前导或尾随 NA
s
G。 Grothendieck 提出了使用 na.locf0()
而不是 na.locf()
的极好建议,以利用前者的 na.rm = FALSE
默认值。当初始值或最后一个值是 而不是 NA
时,这两种方法是等效的,但是当您的列以 NA
开始或结束时,我们需要 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
一个数据框:
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
我想用两个最连续值的平均值替换 NA 值。例如 df[5,2]
是 NA
但我们可以将其替换为 5 和 44 的平均值:
df[5,2] <- (df[4,2]+df[6,2])/2
df[5,2]
[1] 24.5
但是,如果连续值也是NA
,则无法完成此操作。用 df[5,1]
和 df[7,1]
之间的平均值替换 df[6,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
您将看到一个数据框,其中包含数据集中 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
}
唉,我无法通过所有的 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
我们可以为此使用 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
这里,"locf"代表last observation carried forward,用最后一个观测值替换NA
值;使用 fromLast
参数,您可以使用最近的 previous 观察,或最近的 subsequent 观察。我们想要上一个观察值和下一个观察值的平均值,所以我们只需将 fromLast
结果之和除以二,即 TRUE
和 FALSE
.
更新:前导或尾随 NA
s
G。 Grothendieck 提出了使用 na.locf0()
而不是 na.locf()
的极好建议,以利用前者的 na.rm = FALSE
默认值。当初始值或最后一个值是 而不是 NA
时,这两种方法是等效的,但是当您的列以 NA
开始或结束时,我们需要 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