根据周围的值重新编码向量中的值

Recode a value in a vector based on surrounding values

如果 0 前后有三个 1,我正在尝试以编程方式将变量从 0 更改为 1

例如,如果向量中的数字为 1110111,然后我想将 0 更改为 1

这里是 data.frame df 中向量 dummy_code 中的数据:

original_df <- data.frame(dummy_code = c(1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1))

以下是我尝试重新编码值的方法:

desired_df <- data.frame(dummy_code = c(1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1)

我试过使用the function fill in the package tidyr,但这会填补缺失值,所以它不起作用。如果我要重新编码缺少的 0 值,那么这也不起作用,因为它只是将每个 NA 编码为 1,而我只想编码每个 NA 被三个 1s 包围为 1.

有没有办法以编程方式高效地执行此操作?

这里是 one-liner 使用来自动物园的 rollapply

library(zoo)

rollapply(c(0, 0, 0, x, 0, 0, 0), 7, function(x) if (all(x[-4] == 1)) 1 else x[4])
##  [1] 1 0 0 1 1 1 1 1 1 1 0 0 1

注意: 使用的输入是:

x <- c(1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1)

rle 替代方案,使用来自@G 的 x。格洛腾迪克的回答:

r <- rle(x)

查找三个 1 的 运行 的索引:

i1 <- which(r$lengths == 3 & r$values == 1)

检查 0 周围的“1 个索引”中的哪些索引,并获取要替换的 0 的索引:

i2 <- i1[which(diff(i1) == 2)] + 1

将相关的0替换为1:

r$values[i2] <- 1

在更新后的 运行 上反转 rle 操作:

inverse.rle(r)
# [1] 1 0 0 1 1 1 1 1 1 1 0 0 1

基于 data.table::rleid 的类似解决方案,稍微更紧凑,也许更易于阅读:

library(data.table)
d <- data.table(x)

计算每个运行的长度:

d[ , n := .N, by = rleid(x)]

对于"x"为零且1的前后运行长度为3,设置"x"为1:

d[x == 0 & shift(n) == 3 & shift(n, type = "lead") == 3, x := 1]
d$x
# [1] 1 0 0 1 1 1 1 1 1 1 0 0 1