修改向量以仅包含升序元素
Modifying vector to contain only ascending elements
我有一个要修改的矢量,以便它只包含与前一个元素相等或大于前一个元素的元素。该向量表示一种现象,该现象应该只会增加或保持不变(即按天计算的累计死亡人数),但报告错误会导致元素少于前一个元素。我想通过用以前的元素替换元素来纠正这个问题,直到矢量满足上述条件。
原始数据:1 3 3 6 8 10 7 9 15 12
需要修改的数据:1 3 3 6 6 6 7 9 9 12
library(zoo)
raw <- c(1, 3, 3, 6, 8, 10, 7, 9, 15, 12)
replace.errors <- function(x){
x %>%
replace(diff(x) < 0, NA) %>%
na.locf(na.rm=FALSE)
}
replace.errors(raw)
# [1] 1 3 3 6 8 8 7 9 9 12
如果需要替换一行中的多个顺序元素(8 和 10),我的函数将不起作用,因为它只会向前拉一个仍然大于下一个的元素。
data.table
选项使用 nafill
和 cummin
nafill(replace(raw, rev(cummin(rev(raw))) != raw, NA), type = "locf")
给予
> nafill(replace(raw, rev(cummin(rev(raw))) != raw, NA), type = "locf")
[1] 1 3 3 6 6 6 7 9 9 12
按照上述方法的类似想法,您的函数 replace.errors
可以定义为
replace.errors <- function(x){
x %>%
replace(rev(cummin(rev(.))) != (.), NA) %>%
na.locf()
}
这样
> replace.errors(raw)
[1] 1 3 3 6 6 6 7 9 9 12
另一种选择是像下面这样定义用户函数
f <- function(v) {
for (k in which(c(FALSE, diff(v) < 0))) {
p <- max(v[v < v[k]])
v <- replace(v, tail(which(v == p), 1):(k - 1), p)
}
v
}
这给出了
> f(raw)
[1] 1 3 3 6 6 6 7 9 9 12
Base R 使用@ThomasIsCoding 出色的替换逻辑:
# Replace values breaching condition with NA: scrubbed => integer vector
scrubbed <- replace(raw, rev(cummin(rev(raw))) != raw, NA_integer_)
# i) Interpolate constants:
res <- na.omit(scrubbed)[cumsum(!is.na(scrubbed))]
# OR
# ii) Interpolate constants using approx()
res <- approx(scrubbed, method = "constant", n = length(scrubbed))$y
或者在一个表达式中:
approx(
replace(raw, rev(cummin(rev(raw))) != raw, NA_integer_),
method = "constant",
n = length(raw)
)$y
这听起来有点低效,但它可能仍然是最好的选择:
replace_errors <- function(raw) {
while (is.unsorted(raw)) {
raw <- raw[c(TRUE, diff(raw) >= 0)]
}
raw
}
我有一个要修改的矢量,以便它只包含与前一个元素相等或大于前一个元素的元素。该向量表示一种现象,该现象应该只会增加或保持不变(即按天计算的累计死亡人数),但报告错误会导致元素少于前一个元素。我想通过用以前的元素替换元素来纠正这个问题,直到矢量满足上述条件。
原始数据:1 3 3 6 8 10 7 9 15 12
需要修改的数据:1 3 3 6 6 6 7 9 9 12
library(zoo)
raw <- c(1, 3, 3, 6, 8, 10, 7, 9, 15, 12)
replace.errors <- function(x){
x %>%
replace(diff(x) < 0, NA) %>%
na.locf(na.rm=FALSE)
}
replace.errors(raw)
# [1] 1 3 3 6 8 8 7 9 9 12
如果需要替换一行中的多个顺序元素(8 和 10),我的函数将不起作用,因为它只会向前拉一个仍然大于下一个的元素。
data.table
选项使用 nafill
和 cummin
nafill(replace(raw, rev(cummin(rev(raw))) != raw, NA), type = "locf")
给予
> nafill(replace(raw, rev(cummin(rev(raw))) != raw, NA), type = "locf")
[1] 1 3 3 6 6 6 7 9 9 12
按照上述方法的类似想法,您的函数 replace.errors
可以定义为
replace.errors <- function(x){
x %>%
replace(rev(cummin(rev(.))) != (.), NA) %>%
na.locf()
}
这样
> replace.errors(raw)
[1] 1 3 3 6 6 6 7 9 9 12
另一种选择是像下面这样定义用户函数
f <- function(v) {
for (k in which(c(FALSE, diff(v) < 0))) {
p <- max(v[v < v[k]])
v <- replace(v, tail(which(v == p), 1):(k - 1), p)
}
v
}
这给出了
> f(raw)
[1] 1 3 3 6 6 6 7 9 9 12
Base R 使用@ThomasIsCoding 出色的替换逻辑:
# Replace values breaching condition with NA: scrubbed => integer vector
scrubbed <- replace(raw, rev(cummin(rev(raw))) != raw, NA_integer_)
# i) Interpolate constants:
res <- na.omit(scrubbed)[cumsum(!is.na(scrubbed))]
# OR
# ii) Interpolate constants using approx()
res <- approx(scrubbed, method = "constant", n = length(scrubbed))$y
或者在一个表达式中:
approx(
replace(raw, rev(cummin(rev(raw))) != raw, NA_integer_),
method = "constant",
n = length(raw)
)$y
这听起来有点低效,但它可能仍然是最好的选择:
replace_errors <- function(raw) {
while (is.unsorted(raw)) {
raw <- raw[c(TRUE, diff(raw) >= 0)]
}
raw
}