3

对于给定的数据框,我想根据一些布尔值对其进行拆分,然后将标签应用于该行和之前的行,直到该点

假设以下数据框:

test <- data.frame(x = 1:10, y = c(F, F, F, T, F, F, T, F, F, F))

我最终想创建一个新列,其中包含数据框特定部分的标签。理想情况下,如下所示:

x   y   z
1   F   1
2   F   1
3   F   1
4   T   1
5   F   2
6   F   2
7   T   2
8   F   3
9   F   3
10  F   3

我目前的想法是,我需要使用类似于以下(但不完全是)的函数遍历数据帧:

label.portion <- function(test) {
  for (i in 1:nrow(test)) {
    z <- 1
    if(test$y[i]) { z <- z + 1 }
    return(z)
  }
}

最好/最简单的方法是什么?任何帮助深表感谢。

4

4 回答 4

4

您的z列可以构建为

z <- with(test, sum(y)-rev(cumsum(rev(y)))+1)

根据您的示例,为了使每个新z值都从 aFALSE y之后的 a开始。TRUE y

然后你可以做得到cbind(test, z)你想要的。

于 2013-03-26T02:27:14.980 回答
4

一种衬垫解决方案使用transform

transform(test,z= cumsum(c(0,diff(y)) == -1)+1)

    x     y z
1   1 FALSE 1
2   2 FALSE 1
3   3 FALSE 1
4   4  TRUE 1
5   5 FALSE 2
6   6 FALSE 2
7   7  TRUE 2
8   8 FALSE 3
9   9 FALSE 3
10 10 FALSE 3
于 2013-03-26T02:41:35.733 回答
3

另一种衬里解决方案,将比其他解决方案稍快(除了data.table

test <- data.frame(x = 1:10, y = c(F, F, F, T, F, F, T, F, F, F))
test$z <- c(1, head(cumsum(test$y), -1) + 1)
test
##     x     y z
## 1   1 FALSE 1
## 2   2 FALSE 1
## 3   3 FALSE 1
## 4   4  TRUE 1
## 5   5 FALSE 2
## 6   6 FALSE 2
## 7   7  TRUE 2
## 8   8 FALSE 3
## 9   9 FALSE 3
## 10 10 FALSE 3

提供的其他解决方案的基准(不包括 data.table)

test <- data.frame(x = 1:1e+05, y = sample(c(T, F), size = 1e+05, replace = TRUE))
microbenchmark(c(1, head(cumsum(test$y), -1) + 1), cumsum(c(0, diff(test$y)) == -1) + 1, with(test, sum(y) - rev(cumsum(rev(y))) + 
    1), times = 100)
## Unit: milliseconds
##                                          expr      min       lq   median       uq       max neval
##            c(1, head(cumsum(test$y), -1) + 1) 1.685473 1.758474 1.865409 4.647218  5.091512   100
##          cumsum(c(0, diff(test$y)) == -1) + 1 4.064867 4.379714 6.936561 7.338810  7.657961   100
##  with(test, sum(y) - rev(cumsum(rev(y))) + 1) 2.568766 2.720395 5.396096 5.701176 30.642436   100
于 2013-03-26T03:05:42.160 回答
2

这是一种使用na.locffromxts和 data.table 编码优雅(和效率)的方法

library(data.table)
library(xts) # for na.locf
test <- data.table(test)


test[(y), grp := seq_along(y)][, grp := na.locf(grp, fromLast = TRUE)]
test[is.na(grp), grp := max(test[, grp], na.rm =TRUE) + 1L]

还有一种更清晰、更快捷的方法

test[, grp := {xx <- diff(c(0,.I[y], length(.I))); rep.int(seq_along(xx),xx)}]

请注意,diff使用在 中实现的 for 循环R,因此 Rcpp 糖实现)会更快(我确信 cpp 函数会将其中大部分从水中吹走)

于 2013-03-26T02:45:18.907 回答