如何在R中使用线性模型分别替换缺失值(NA)

4

我查看了一些网页(但它们的结果不符合我的需求):

我想编写一个函数,可以实现以下功能:

假设有一个向量a

a = c(100000, 137862, NA, NA, NA, 178337, NA, NA, NA, NA, NA, 295530)

首先,在单个和连续的NA之前和之后找到数值。 在这种情况下是 137862, NA, NA, NA, 178337178337, NA, NA, NA, NA, NA, 295530

其次,计算每个部分的斜率,然后替换NA

# 137862, NA, NA, NA, 178337
slope_1 = (178337 - 137862)/4

137862 + slope_1*1 # 1st NA replace with 147980.8
137862 + slope_1*2 # 2nd NA replace with 158099.5
137862 + slope_1*3 # 3rd NA replace with 168218.2

# 178337, NA, NA, NA, NA, NA, 295530

slope_2 = (295530 - 178337)/6

178337 + slope_2*1 # 4th NA replace with 197869.2
178337 + slope_2*2 # 5th NA replace with 217401.3
178337 + slope_2*3 # 6th NA replace with 236933.5
178337 + slope_2*4 # 7th NA replace with 256465.7
178337 + slope_2*5 # 8th NA replace with 275997.8

最后,期望的向量应该是这个:

a_without_NA = c(100000, 137862, 147980.8, 158099.5, 168218.2, 178337, 197869.2, 217401.3, 
                 236933.5, 256465.7, 275997.8, 295530)

如果开头是单个或连续的NA,则会被保留。

# NA at begining
b = c(NA, NA, 1, 3, NA, 5, 7)

# 3, NA, 5
slope_1 = (5-3)/2
3 + slope_1*1 # 3rd NA replace with 4
b_without_NA = c(NA, NA, 1, 3, 4, 5, 7)

# NA at ending
c = c(1, 3, NA, 5, 7, NA, NA)

# 3, NA, 5
slope_1 = (5-3)/2
3 + slope_1*1 # 1st NA replace with 4
c_without_NA = c(1, 3, 4, 5, 7, NA, NA)

注意:在我的实际情况中,向量的每个元素都是递增的(vector[n + 1] > vector[n])。
我知道原理,但不知道如何编写自定义函数来实现此目的。
非常感谢任何帮助!

1
@ akrun,抱歉,是我的错误,我已经更新了我的代码。 - zhiwei li
4个回答

5

zoona.approx可以帮助:

a = c(100000, 137862, NA, NA, NA, 178337, NA, NA, NA, NA, NA, 295530)
zoo::na.approx(a, na.rm = FALSE)

# [1] 100000.0 137862.0 147980.8 158099.5 168218.2 178337.0 197869.2 217401.3
# [9] 236933.5 256465.7 275997.8 295530.0

b = c(NA, NA, 1, 3, NA, 5, 7)

zoo::na.approx(b, na.rm = FALSE)
#[1] NA NA  1  3  4  5  7

c = c(1, 3, NA, 5, 7, NA, NA)
zoo::na.approx(c, na.rm = FALSE)
#[1]  1  3  4  5  7 NA NA

我遇到了一个新问题。如果您能看一下,我会很感激。https://stackoverflow.com/questions/67427949/how-to-use-none-standard-evaluation-in-r - zhiwei li
抱歉打扰您,我有一个新问题,如果您有时间帮我看一下,我会非常感激。(https://dev59.com/BcHqa4cB1Zd3GeqPuzdY) - zhiwei li

3
为此,我定义了一个自定义函数:
my_replace_na <- function(x) {
  non <- which(!is.na(x))          # Here we extract the indices of non NA values
  
  for(i in 1:(length(non)-1)) {
    if(non[i+1] - non[i] > 1) {
      c <- non[i+1]
      b <- non[i]
      
      for(i in 1:(c - b - 1)) {
        x[b+i] <- x[b]  + ((x[c] - x[b]) / (c - b))*i
      }
    }
  }
  x
}

a <- c(100000, 137862, NA, NA, NA, 178337, NA, NA, NA, NA, NA, 295530)
my_replace_na(a)

 [1] 100000.0 137862.0 147980.8 158099.5 168218.2 178337.0 197869.2 217401.3 236933.5 256465.7
[11] 275997.8 295530.0

# NA at begining
d <- c(NA, NA, 1, 3, NA, 5, 7)
my_replace_na(d)

[1] NA NA  1  3  4  5  7

# NA at ending
e <- c(1, 3, NA, 5, 7, NA, NA)
my_replace_na(e)

[1]  1  3  4  5  7 NA NA


3

这里是使用基础R选项的内容,使用approx函数。

> approx(seq_along(a)[!is.na(a)], a[!is.na(a)], seq_along(a))$y
 [1] 100000.0 137862.0 147980.8 158099.5 168218.2 178337.0 197869.2 217401.3
 [9] 236933.5 256465.7 275997.8 295530.0

2

以下是使用data.table的一种方法。获取'a'中连续NA的运行长度ID(rleid)('grp'),创建两个临时列'a1','a2'作为'a'的laglead,并按'grp'分组,基于计算创建'tmp',最后将原始的'a'与该'tmp'进行fcoalesce

library(data.table)
data.table(a)[, grp := rleid(is.na(a))][, 
  c('a1', 'a2') := .(shift(a), shift(a, type = 'lead'))][, 
   tmp := first(a1) + seq_len(.N) *( (last(a2) - first(a1))/(.N + 1)), 
      .(grp)][, fcoalesce(a, tmp)]
#[1] 100000.0 137862.0 147980.8 158099.5 168218.2 178337.0 
#[7] 197869.2 217401.3 236933.5 256465.7 275997.8 295530.0

我遇到了一个新问题。如果您能看一下,我会很感激。https://stackoverflow.com/questions/67427949/how-to-use-none-standard-evaluation-in-r - zhiwei li
抱歉打扰您了,我有一个新问题,如果您有时间帮我看一下,我会非常感激。(https://dev59.com/BcHqa4cB1Zd3GeqPuzdY) - zhiwei li

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接