从其他行获取平均值到当前行
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))
再解释一下:
- mean_top_bot[1] = val[depth = 0] + val[depth = 20]。因为我在深度 0 处没有值,所以会变成 (NA + 18)/2 = 18 (rm.na = TRUE)
- mean_top_bot[2] = val[depth=10] + val[depth=30] = (12+11)/2
- 我手动计算了
mean_top_bot
个值。这就是为什么我在那里有一些错误 :facepal:
使用自合并的解决方案
通过更改 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()
的两个特点派上用场:
width
参数或者采用整数偏移量列表。因此,list(c(-1L, 1L))
引用前后行的值,同时省略当前行。
- 使用
partial = TRUE
,只有 在 范围内的索引子集被传递给 FUN
。例如,对于第一行,偏移量 -1 指的是超出范围的索引 0。因此,只有索引 2(偏移量 1)的值被传递给 mean()
。同样对于最后一行,只有倒数第二个值被传递给 mean()
.
我有一个土壤属性 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))
再解释一下:
- mean_top_bot[1] = val[depth = 0] + val[depth = 20]。因为我在深度 0 处没有值,所以会变成 (NA + 18)/2 = 18 (rm.na = TRUE)
- mean_top_bot[2] = val[depth=10] + val[depth=30] = (12+11)/2
- 我手动计算了
mean_top_bot
个值。这就是为什么我在那里有一些错误 :facepal:
使用自合并的解决方案
通过更改 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()
的两个特点派上用场:
width
参数或者采用整数偏移量列表。因此,list(c(-1L, 1L))
引用前后行的值,同时省略当前行。- 使用
partial = TRUE
,只有 在 范围内的索引子集被传递给FUN
。例如,对于第一行,偏移量 -1 指的是超出范围的索引 0。因此,只有索引 2(偏移量 1)的值被传递给mean()
。同样对于最后一行,只有倒数第二个值被传递给mean()
.