【发布时间】:2019-08-07 14:35:31
【问题描述】:
假设我有:
v <- c(1,2,0,0,0,3,4,4,4,0,0,0,0,5,0)
v
[1] 1 2 0 0 0 3 4 4 4 0 0 0 0 5 0
我想消除连续 0 的数量为 2+(2 或更多)的任何连续 0。所以上面的例子会变成:
1 2 3 4 4 4 5 0
注意:我更喜欢 base-R 解决方案,但其他解决方案是 有趣
【问题讨论】:
假设我有:
v <- c(1,2,0,0,0,3,4,4,4,0,0,0,0,5,0)
v
[1] 1 2 0 0 0 3 4 4 4 0 0 0 0 5 0
我想消除连续 0 的数量为 2+(2 或更多)的任何连续 0。所以上面的例子会变成:
1 2 3 4 4 4 5 0
注意:我更喜欢 base-R 解决方案,但其他解决方案是 有趣
【问题讨论】:
1) na.locf0 这个使用zoo包但是只有一行代码。它利用na.locf0 中的maxgap 参数。用 NA 替换每个 0,用 0 替换其他所有内容。使用 na.locf0 和 maxgap 填充,将其添加到原始向量中,应用 na.omit 删除 NA,使用 c 删除属性。
library(zoo)
c(na.omit(na.locf0(ifelse(v == 0, NA, 0), maxgap = 1) + v))
## [1] 1 2 3 4 4 4 5 0
2) rleid 这使用来自 data.table 的rleid。它比(1)长一点,但仍然相当短。它使用rleid 对数据进行分组,然后为每个组生成一个 NA 或在最后删除 NA 的原始数据。
library(data.table)
fun <- function(x) if (x[1] == 0 & length(x) > 1) NA else x
c(na.omit(ave(v, rleid(v), FUN = fun)))
## [1] 1 2 3 4 4 4 5 0
【讨论】:
rle 的选项。我们可以用rle创建一个逻辑条件,并以此为基础提取values
with(rle(v), {i1 <- !(values == 0 & lengths > 1); rep(values[i1], lengths[i1])})
#[1] 1 2 3 4 4 4 5 0
注意:在以前的版本中,OP' 输出仅返回一个 value。我们只需要使用相同的逻辑将replicate 与lengths 联系起来
或者可以使用rleid使其更紧凑
library(data.table)
v[!(ave(v, rleid(v), FUN = length) > 1 & !v)]
#[1] 1 2 3 4 4 4 5 0
【讨论】:
这是base 中的regex 解决方案:
as.numeric(unlist(strsplit(gsub("(0\\,){2,}","",paste0(v,collapse=",")),",")))
# [1] 1 2 3 4 4 4 5 0
注意在你的问题中你说连续0的数量是2+,但你的例子是3+连续零;如果需要,将 {2,} 更改为 {3,}。
【讨论】:
另一种使用 ave 和 head 和 tail 比较连续值的基本 R 方式
v[!ave(v == 0, cumsum(c(TRUE, head(v, -1) != tail(v, -1))),
FUN = function(x) all(x) & length(x) >= 2)]
#[1] 1 2 3 4 4 4 5 0
【讨论】: