我有一个值为NA
,0
和1
的向量:
x <- c(NA, 0, 0, 1, 1, 1, 1, NA, 0, 0, 0, 0, NA, NA, 1, 1, 1, NA)
#> x
#[1] NA 0 0 1 1 1 1 NA 0 0 0 0 NA NA 1 1 1 NA
每当序列从1
切换到NA
时,我想在该事件之前计算非NAs
的位置,并用该数字替换元素。我期待这个输出:
#> x_output
#[1] NA 6 5 4 3 2 1 NA 0 0 0 0 NA NA 3 2 1 NA
有人有解决方案吗?首选矢量化方法,因为矢量很长,数据集相当大。
答案 0 :(得分:8)
使用rle
定义运行长度,使用ave
创建序列:
x <- c(NA, 0, 0, 1, 1, 1, 1, NA, 0, 0, 0, 0, NA, NA, 1, 1, 1, NA)
fun <- function(x) {
x <- rev(x)
y <- rle(!is.na(x))
y$values[y$values] <- seq_along(y$values[y$values])
y <- inverse.rle(y)
x[!is.na(x)] <- ave(x[!is.na(x)], y[!is.na(x)], FUN = function(x) {
if (x[1] == 0L) return(x)
seq_along(x)
})
rev(x)
}
fun(x)
#[1] NA 6 5 4 3 2 1 NA 0 0 0 0 NA NA 3 2 1 NA
答案 1 :(得分:4)
以下是data.table
的选项。创建一个TRUE / FALSE列的&lt; indx&#39;来标识1到NA的切换。然后,按照逻辑向量(rleid(is.na(x))
)的运行长度id分组,if
在&#39; indx&#39;中有any
TRUE,然后得到与序列相反的顺序行或else
返回&#39; x&#39;并提取列&#39; V1&#39;
library(data.table)
data.table(x)[, indx := shift(shift(x, fill = 0) %in% 1 & is.na(x),
type = 'lead', fill = FALSE)][, if(any(indx)) rev(seq_len(.N)) else
as.integer(x) ,rleid(is.na(x))]$V1
#[1] NA 6 5 4 3 2 1 NA 0 0 0 0 NA NA 3 2 1 NA
答案 2 :(得分:3)
另一种方法
library(dplyr)
start_inds <- which(x == 1 & is.na(lead(x)))
na_inds <- which(is.na(x))
sapply(start_inds, function(x) {
sub_ind = x - na_inds
end_inds = (x - min(sub_ind[sub_ind > 0]) + 1) : x
x[end_inds] <<- rev(seq_along(end_inds))
})
x
#[1] NA 6 5 4 3 2 1 NA 0 0 0 0 NA NA 3 2 1 NA
我们使用来自x
的{{1}}找出NA
等于1且下一个元素为lead
的交叉点,它为我们提供了我们需要的指数向后改变价值。 (dplyr
)。我们计算start_inds
中NA
出现的向量中的所有索引,以便我们可以使用它来获得最接近的na_inds
值。现在,对于每个NA
,我们使用start_inds
减去它的值并计算最接近的na_inds
值,直到我们需要更改值(NA
)。要选择end_inds
,end_inds
和start_ind
之间的差异必须大于0,因为我们需要na_inds
之前的NA
值,我们使用{{ 1}}获取最近的start_ind
值索引。通过使用全局赋值运算符(min
)生成序列NA
来更新值。