从其他行获取平均值到当前行

Get mean value from other rows into current row

我有一个土壤属性 data.table,其中包含不同位置和深度的值。有些值是 NA 所以我想考虑上层和下层的平均值。对于顶层,我会取下一层的值。

我能够创建一个列来指示每一行的上层和下层,并且我考虑进行自我合并。但我完全不知道如何进行。

关于如何执行此操作的任何线索?下面是一个示例 data.table 以及我想要实现的目标。该示例考虑了具有 3 个图层的两个位置。但是我有多个位置,有些位置比其他位置更多。

library(data.table)

# I was able to identify which are the botton and top layers
# using a function to identify the neighboors
dt <- data.table(id = rep(c(1,2), 1, each = 3),
                 depth = c(10, 20, 30, 10, 20, 30),
                 val = c(12, 18, 11, 25, 27, 29),
                 bot_l = c(20, 30, NA, 20, 30, NA),
                 top_l = c(NA, 10, 20, NA, 10, 20))


# How can I calculate the average between top and lowe layers?
dt_desired <- data.table(id = rep(c(1,2), 1, each = 3),
                         depth = c(10, 20, 30, 10, 20, 30),
                         val = c(12, 18, 11, 25, 27, 29),
                         bot_l = c(20, 30, NA, 20, 30, NA),
                         top_l = c(NA, 10, 20, NA, 10, 20)
                         mean_top_bot = c(18, 11.5, 18, 27, 27, 27))

再解释一下:

使用自合并的解决方案

通过更改 by.x 和 by.y` 参数,我能够将 table 与其自身合并。但我有一种感觉,我正在以最糟糕的方式做这件事。

dt1 <- merge(dt, dt[, .SD, .SDcols = !c('bot_l', 'top_l')],
             by.x = c('id', 'bot_l'),
             by.y = c('id', 'depth'),
             all = TRUE)[order(id, depth)]

   id bot_l depth val.x top_l val.y
1:  1    20    10    12    NA    18
2:  1    30    20    18    10    11
3:  1    NA    30    11    20    NA
4:  1    10    NA    NA    NA    12
5:  2    20    10    25    NA    27
6:  2    30    20    27    10    29
7:  2    NA    30    29    20    NA
8:  2    10    NA    NA    NA    25

有没有更简单的方法来做到这一点?

直接使用data.table::shift而不计算“top”和“bot”层应该更容易。

dt <- data.table(id = rep(c(1,2), 1, each = 3),
                 depth = c(10, 20, 30, 10, 20, 30),
                 val = c(12, 18, 11, 25, 27, 29))

dt[, v := rowMeans(data.table::setDT(data.table::shift(val, 
                                                       c(1, - 1))),
                   na.rm = TRUE), 
   by = id]

相同,但使用了 maggrittr :

library(magrittr)  

dt[, v := data.table::shift(val, c(1, -1)) %>% data.table::setDT() %>% rowMeans(na.rm = TRUE), 
   by = id]

上面的代码为给定的深度计算上一个和下一个 val 之间的平均值。我假设 value 和 top/bot 层之间的差距是一个,并且数据已经按 id 和 depth 排序,如您的示例所示。

我花了一段时间才弄清楚,但这也可以通过 滚动平均值:

来解决
dt[, mean_top_bot := 
     zoo::rollapply(val, width = list(c(-1L, 1L)), FUN = mean, partial = TRUE), id][]
   id depth val bot_l top_l mean_top_bot
1:  1    10  12    20    NA           18
2:  1    20  18    30    10         11.5
3:  1    30  11    NA    20           18
4:  2    10  25    20    NA           27
5:  2    20  27    30    10           27
6:  2    30  29    NA    20           27

zoo::rollapply()的两个特点派上用场:

  1. width 参数或者采用整数偏移量列表。因此,list(c(-1L, 1L)) 引用前后行的值,同时省略当前行。
  2. 使用 partial = TRUE,只有 范围内的索引子集被传递给 FUN。例如,对于第一行,偏移量 -1 指的是超出范围的索引 0。因此,只有索引 2(偏移量 1)的值被传递给 mean()。同样对于最后一行,只有倒数第二个值被传递给 mean().