我正在尝试解决以下问题。 我有一个小标题:
> tibble( signal = c(0,1,0,0,1,0,0,1,1,1,1,1,1,0), days =0)
# A tibble: 14 x 2
signal days
<dbl> <dbl>
1 0 0
2 1 0
3 0 0
4 0 0
5 1 0
6 0 0
7 0 0
8 1 0
9 1 0
10 1 0
11 1 0
12 1 0
13 1 0
14 0 0
我需要通过以下方式填写“天”列:
因此,结果将如下所示:
signal days
<dbl> <dbl>
1 0 0
2 1 1
3 0 2
4 0 3
5 1 4
6 0 0
7 0 0
8 1 1
9 1 2
10 1 3
11 1 4
12 1 1
13 1 2
14 0 3
我可以使用for循环来做到这一点,但是很难使用dplyr将其向量化。
感谢任何帮助!
答案 0 :(得分:3)
data.table::set()
library(data.table)
i <- 1L
n <- nrow(df)
while (i < n) {
if (df$signal[i] == 1) {
k <- min(i+3L, n)
set(df, i = (i:k), j = "days", 1L:(k-i+1L))
i <- i+4L
} else {
i <- i+1L
}
}
# signal days
# 1 0 0
# 2 1 1
# 3 0 2
# 4 0 3
# 5 1 4
# 6 0 0
# 7 0 0
# 8 1 1
# 9 1 2
# 10 1 3
# 11 1 4
# 12 1 1
# 13 1 2
# 14 0 3
答案 1 :(得分:2)
这是一个Rcpp
解决方案。尽管它包含一个循环,但是与基于R的循环相比,其开销非常低,并且可能与您将获得的速度一样快:
Rcpp::cppFunction("IntegerVector fill_column(IntegerVector v) {
bool flag = false;
int counter = 1;
for(int i = 0; i < v.length(); ++i) {
if(flag){
v[i] = counter++;
if(counter == 5) {
flag = false;
counter = 1;
}
} else {
if(v[i] == 1) {
v[i] = counter++;
flag = true;
}
}
}
return v;
}")
这允许您使用dplyr内部的功能:
df %>% mutate(days = fill_column(signal))
##> A tibble: 14 x 2
#> signal days
#> <dbl> <int>
#> 1 0 0
#> 2 1 1
#> 3 0 2
#> 4 0 3
#> 5 1 4
#> 6 0 0
#> 7 0 0
#> 8 1 1
#> 9 1 2
#> 10 1 3
#> 11 1 4
#> 12 1 1
#> 13 1 2
#> 14 0 3
答案 2 :(得分:2)
这是通过定义自定义函数f
来实现的基础R解决方案,该函数有助于根据给定的signals
找出从哪里开始向量
f <- function(signals) {
k <- 1
v <- which(signals == 1)
while (k < length(v)) {
if (v[k + 1] - v[k] < 4) {
v <- v[-(k + 1)]
k <- 1
} else {
k <- k + 1
}
}
v
}
然后,如果我们运行以下for
循环
for (i in f(df$signal)) {
fill <- i:min(i + 3, nrow(df))
df$days[fill] <- seq_along(fill)
}
我们会看到的
> df
signal days
1 0 0
2 1 1
3 0 2
4 0 3
5 1 4
6 0 0
7 0 0
8 1 1
9 1 2
10 1 3
11 1 4
12 1 1
13 1 2
14 0 3