如果被少于五个连续零包围,则将向量中的零更改为一
Change zero to ones in vector if surrounded by less than five consecutive zeros
我有一个 0
s 和 1
s 的向量,我想识别 0
s 的字符串被 1
s 包围的索引。如果 1
s 之间的 0
s 的数量小于或等于 5,我想将这些零更改为 1
s.
这是一个例子:
> x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
7,8,9位置我只有3个零,需要改成1,其他零都超过5个,不用改。
生成的向量应如下所示:
> x_converted <- c(0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1)
我正在使用 for
循环和 if else
语句来执行此操作,但我确信必须有更快的方法来执行此操作。
谢谢。
rle()
(run-length-encoding) 函数使这变得非常简单。
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
r <- rle(x)
## modify values appropriately
r$values[r$values==0 & r$lengths<=5] <- 1
## convert back to full vector
x_new <- rep(r$values, r$lengths)
## [1] 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
然而,这仍然需要针对文字边缘情况进行一些调整 — 这已将 3 个零的初始 运行 转换为 1。也许
n <- length(r$values)
rv_int <- r$values[2:(n-1)]
rl_int <- r$lengths[2:(n-1)]
rv_int[rv_int == 0 &
rl_int <= 5] <- 1
x_new <- rep(c(r$values[1], rv_int, r$values[n]),
c(r$lengths[1], rl_int, r$lengths[n]))
您可以使用 rle()
获取 运行。然后根据 运行 的长度更改它,通过查看 cumprod()
.
排除第一个 运行
x_rle <- rle(x)
x_0 <- cumprod(x_rle$values == 0)
x_rev_0 <- rev(cumprod(rev(x_rle$values) == 0))
x_rle$values <- ifelse(
x_rle$lengths > 5 | x_0 | x_rev_0,
x_rle$values,
1
)
rep(x_rle$values, x_rle$lengths)
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
With data.table::rleid
: rleid
创建 run-length 类型组 ID,在 ave
中用作分组因子。 ave
然后对 r
.
定义的组执行函数
r <- data.table::rleid(x)
# [1] 1 1 1 2 2 2 3 3 3 4 4 5 5 5 5 5 5 6 6 6 6
sub <- !r %in% c(1, max(r))
x[sub] <- ave(x[sub], r[sub], FUN = function(x) ifelse(length(x) <= 3 & x == 0, 1, x))
# [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
rle
的可能解决方案,它不会改变 x
开头或结尾的零短序列:
# create the run length encoding
r <- rle(x)
# create an index of which zero's should be changed
i <- r$values == 0 & r$lengths < 5 &
c(tail(r$values, -1) == 1, FALSE) &
c(FALSE, head(r$values, -1) == 1)
# set the appropriate values to 1
r$values[i] <- 1
# use the inverse of rle to recreate the vector
inverse.rle(r)
给出:
[1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
一种不同的方法,基于将 x
转换为字符串然后再转换回数字向量:
library(tidyverse)
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
x %>% str_c(collapse = "") %>%
str_replace_all("(?<=1)0{1,5}(?=1)", \(x) str_dup("1", nchar(x))) %>%
str_split("") %>% flatten %>% as.numeric
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
或 purrr::walk
和 rle
:
library(purrr)
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
z <- rle(x)
walk(1:(length(z$values)-3),
~ if (all(z$values[.x:(.x+2)] == c(1,0,1)) & z$lengths[.x+1] <= 5)
z$values[.x+1] <<- 1)
inverse.rle(z)
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
我有一个 0
s 和 1
s 的向量,我想识别 0
s 的字符串被 1
s 包围的索引。如果 1
s 之间的 0
s 的数量小于或等于 5,我想将这些零更改为 1
s.
这是一个例子:
> x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
7,8,9位置我只有3个零,需要改成1,其他零都超过5个,不用改。
生成的向量应如下所示:
> x_converted <- c(0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1)
我正在使用 for
循环和 if else
语句来执行此操作,但我确信必须有更快的方法来执行此操作。
谢谢。
rle()
(run-length-encoding) 函数使这变得非常简单。
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
r <- rle(x)
## modify values appropriately
r$values[r$values==0 & r$lengths<=5] <- 1
## convert back to full vector
x_new <- rep(r$values, r$lengths)
## [1] 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
然而,这仍然需要针对文字边缘情况进行一些调整 — 这已将 3 个零的初始 运行 转换为 1。也许
n <- length(r$values)
rv_int <- r$values[2:(n-1)]
rl_int <- r$lengths[2:(n-1)]
rv_int[rv_int == 0 &
rl_int <= 5] <- 1
x_new <- rep(c(r$values[1], rv_int, r$values[n]),
c(r$lengths[1], rl_int, r$lengths[n]))
您可以使用 rle()
获取 运行。然后根据 运行 的长度更改它,通过查看 cumprod()
.
x_rle <- rle(x)
x_0 <- cumprod(x_rle$values == 0)
x_rev_0 <- rev(cumprod(rev(x_rle$values) == 0))
x_rle$values <- ifelse(
x_rle$lengths > 5 | x_0 | x_rev_0,
x_rle$values,
1
)
rep(x_rle$values, x_rle$lengths)
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
With data.table::rleid
: rleid
创建 run-length 类型组 ID,在 ave
中用作分组因子。 ave
然后对 r
.
r <- data.table::rleid(x)
# [1] 1 1 1 2 2 2 3 3 3 4 4 5 5 5 5 5 5 6 6 6 6
sub <- !r %in% c(1, max(r))
x[sub] <- ave(x[sub], r[sub], FUN = function(x) ifelse(length(x) <= 3 & x == 0, 1, x))
# [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
rle
的可能解决方案,它不会改变 x
开头或结尾的零短序列:
# create the run length encoding
r <- rle(x)
# create an index of which zero's should be changed
i <- r$values == 0 & r$lengths < 5 &
c(tail(r$values, -1) == 1, FALSE) &
c(FALSE, head(r$values, -1) == 1)
# set the appropriate values to 1
r$values[i] <- 1
# use the inverse of rle to recreate the vector
inverse.rle(r)
给出:
[1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
一种不同的方法,基于将 x
转换为字符串然后再转换回数字向量:
library(tidyverse)
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
x %>% str_c(collapse = "") %>%
str_replace_all("(?<=1)0{1,5}(?=1)", \(x) str_dup("1", nchar(x))) %>%
str_split("") %>% flatten %>% as.numeric
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
或 purrr::walk
和 rle
:
library(purrr)
x <- c(0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1)
z <- rle(x)
walk(1:(length(z$values)-3),
~ if (all(z$values[.x:(.x+2)] == c(1,0,1)) & z$lengths[.x+1] <= 5)
z$values[.x+1] <<- 1)
inverse.rle(z)
#> [1] 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1