我最近在寻找有关如何使用dplyr(dplyr override all but the first occurrences of a value within a group)抑制组中第一次出现的值的建议。
解决方案是一个非常聪明的解决方案,现在我正努力找到同样有效的东西,以防我只需要抑制n个下一个值。
例如,在下面的代码中,我创建了一个新的"标记"柱:
library('dplyr')
data(iris)
set.seed(1)
iris$tag <- sample(c(0,1), 150, replace=TRUE, prob = c(0.7, 0.3))
giris <- iris %>% group_by(Species)
# Source: local data frame [150 x 6]
# Groups: Species [3]
#
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species tag
# (dbl) (dbl) (dbl) (dbl) (fctr) (dbl)
# 1 5.1 3.5 1.4 0.2 setosa 0
# 2 4.9 3.0 1.4 0.2 setosa 0
# 3 4.7 3.2 1.3 0.2 setosa 0
# 4 4.6 3.1 1.5 0.2 setosa 1
# 5 5.0 3.6 1.4 0.2 setosa 0
# 6 5.4 3.9 1.7 0.4 setosa 1
# 7 4.6 3.4 1.4 0.3 setosa 1
# 8 5.0 3.4 1.5 0.2 setosa 0
# 9 4.4 2.9 1.4 0.2 setosa 0
# 10 4.9 3.1 1.5 0.1 setosa 0
# .. ... ... ... ... ... ...
在setosa组行中:4,6,7,...被标记为&#34; 1&#34; s。在任何&#34; 1&#34;出现之后,我试图在接下来的两行中抑制&#34; 1&#34; s(即将它们转换为&#34; 0&#34; s)。换句话说,行#5和#6应设置为&#34; 0&#34;但#7应保持不受影响。在这种情况下,第7行恰好是&#34; 1&#34;,因此第8行和第9行应该设置为&#34; 0&#34; s等等......
有关如何在dplyr中执行此操作的任何提示?这个包非常强大但是出于某种原因,掌握所有细微之处对我来说是一个精神上的挑战......
更多例子: 在:0 0 1 1的情况下,输出应为0 0 1 0 如果:0 0 1 1 1 1 1,输出应为0 0 1 0 0 1 0
答案 0 :(得分:4)
除了循环之外,我无法想到更好的方法:
flip_followers = function(tag, nf = 2L){
w = which(tag==1L)
keep = rep(TRUE, length(w))
for (i in seq_along(w)) if (keep[i]) keep[match(w[i]+seq_len(nf), w)] = FALSE
tag[w[!keep]] = 0L
tag
}
giris %>% mutate(tag = flip_followers(tag))
Source: local data frame [150 x 6]
Groups: Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species tag
(dbl) (dbl) (dbl) (dbl) (fctr) (dbl)
1 5.1 3.5 1.4 0.2 setosa 0
2 4.9 3.0 1.4 0.2 setosa 0
3 4.7 3.2 1.3 0.2 setosa 0
4 4.6 3.1 1.5 0.2 setosa 1
5 5.0 3.6 1.4 0.2 setosa 0
6 5.4 3.9 1.7 0.4 setosa 0
7 4.6 3.4 1.4 0.3 setosa 1
8 5.0 3.4 1.5 0.2 setosa 0
9 4.4 2.9 1.4 0.2 setosa 0
10 4.9 3.1 1.5 0.1 setosa 0
.. ... ... ... ... ... ...
对于可能的加速,您可以将循环切换为if (keep[i]) keep[i+seq_len(nf)][match(w[i]+seq_len(nf), w[i+seq_len(nf)])] = FALSE
,以便match
仅搜索nf
的下一个w
元素。如果这是一个严重的问题,我相信Rcpp会更快。
答案 1 :(得分:3)
有点笨拙,但似乎你必须走向向量,无论
f <- function(x, repl = c(1,0,0)) {
sx <- seq(x)
for (ii in seq_along(x))
if (x[ii] == repl[1L]) ## thanks to @Frank for catching
x[ii:(ii + length(repl) - 1)] <- repl
x[sx]
}
(x <- c(0,0,1,1,1,1,1)); f(x)
# [1] 0 0 1 1 1 1 1
# [1] 0 0 1 0 0 1 0
(x <- c(0,0,1,0,1,0,1,1)); f(x)
# [1] 0 0 1 0 1 0 1 1
# [1] 0 0 1 0 0 0 1 0
和你的例子
set.seed(1)
head(n = 10,
cbind(tag <- sample(c(0,1), 150, replace=TRUE, prob = c(0.7, 0.3)),
tag2 = f(tag)))
# [1,] 0 0
# [2,] 0 0
# [3,] 0 0
# [4,] 1 1
# [5,] 0 0
# [6,] 1 0
# [7,] 1 1
# [8,] 0 0
# [9,] 0 0
# [10,] 0 0
你可以用你想要的任何东西替换
(x <- c(0,0,1,1,1,1,1)); f(x, c(1,0,0,0))
# [1] 0 0 1 1 1 1 1
# [1] 0 0 1 0 0 0 1
(x <- c(0,0,1,1,1,1,1)); f(x, 1:3)
# [1] 0 0 1 1 1 1 1
# [1] 0 0 1 2 3 1 2
## courtesy of @Frank this would also work
(x <- c(0,0,1,1,0,0,1)); f(x, 0:2)
# [1] 0 0 1 1 0 0 1
# [1] 0 1 2 1 0 1 2
答案 2 :(得分:3)
对我而言,如果使用累积缩小来跟踪折射周期,这在语义上更清晰。
suppress <- function(x, w) {
r <- Reduce(function(d,i) if(i&!d) w else max(0,d-1), x, init=0, acc=TRUE)[-1]
x * (r==w)
}
示例
suppress(c(0,0,1,1,1,1,1), 2)
#> [1] 0 0 1 0 0 1 0