为一定长度的正值或负值的运行添加索引

时间:2017-11-21 13:27:25

标签: r loops

我有一个数据帧,其中包含100.000行。它看起来像这样:

 Value
 1
 2
-1
-2
 0
 3
 4
-1
 3

我想创建一个额外的列(B列)。其中包括0和1。

它基本上是0,但是当一行中有5个数据点为正或负时,则应该给出1.但是,只有当它们在一行中时(例如:当行是正数时,有负数......计数应重新开始)。

Value    B
 1       0
 2       0
 1       0
 2       0
 2       1
 3       1
 4       1
-1       0
 3       0

我尝试了不同的循环,但它没有用。我还尝试将整个DF转换为列表(并在列表上循环)。不幸的是没有尽头。

3 个答案:

答案 0 :(得分:1)

这是一种使用rollmean包中的zoo函数的方法。

set.seed(1000)
df = data.frame(Value = sample(-9:9,1000,replace=T))
sign = sign(df$Value)
library(zoo)
rolling = rollmean(sign,k=5,fill=0,align="right")
df$B = as.numeric(abs(rolling) == 1)

我生成了1000个正值和负值的值。

  • 提取值的sign - 这对于负数为-1,对于正数为1,对于0为0
  • 计算5个值的右对齐滚动平均值(它将平均x [1:5],x [2:6],...)。如果一行中的所有值都是正数或负数(分别为)
  • ,则为1或-1
  • 取绝对值并将比较存储为1.这是一个逻辑向量,根据您的条件变为0和1。

注意 - 不需要循环。这一切都可以进行矢量化(一旦我们计算了滚动平均值)。

答案 1 :(得分:0)

这会奏效。这不是最有效的方法,但逻辑非常透明 - 只需检查五个相邻行的每个序列是否只有一个唯一的符号(即+, - 或0):

dat <- data.frame(Value=c(1,2,1,2,2,3,4,-1,3))

dat$new_col <- NA
dat$new_col[1:4] <- 0

for (x in 5:nrow(dat)){
  if (length(unique(sign(dat$Value[(x-4):x])))==1){
    dat$new_col[x] <- 1
  } else {
    dat$new_col[x] <- 0
  }
}

答案 2 :(得分:0)

使用cumsum(...diff(...) <condition>)惯用法创建分组变量,使用ave计算每个组中的索引。

d$B2 <- ave(d$Value, cumsum(c(0, diff(sign(d$Value)) != 0)), FUN = function(x){
  as.integer(seq_along(x) > 4)})

#   Value B B2
# 1     1 0  0
# 2     2 0  0
# 3     1 0  0
# 4     2 0  0
# 5     2 1  1
# 6     3 1  1
# 7     4 1  1
# 8    -1 0  0
# 9     3 0  0