检查多行中是否存在条件

Checking for condition present in multiple rows

我有一个包含 LastPrice 和 KCT 列的数据框。然后代码创建第三列 SignalBinary,并在连续三行的 LastPrice > KCT 时在其上记录 1。

(例如在 SignalBinary[1] 中记录一个 1 时 LastPrice[1] > KCT[1] AND LastPrice[2] > KCT[2] AND LastPrice[3] > KCT[3],每一行依此类推)

df <- data.frame(LastPrice = c( 1221, 1220, 1220, 1217, 1216,  1218 , 1216, 1216, 1217, 1220, 1219, 1218, 1220, 1216, 1217, 1218, 1218, 1207, 1206, 1205), KCT = c( 1218, 1218, 1219, 1218, 1221,  1217 , 1217, 1216, 1219, 1216, 1217, 1216, 1219, 1217, 1218, 1217, 1217, 1217, 1219, 1217))

for(j in 1:nrow(df)) {
  df$SignalBinary[j] <- ifelse (  
    df$LastPrice[j] > df$KCT[j] 
    & df$LastPrice[j+1] > df$KCT[j+1] 
    & df$LastPrice[j+2] > df$KCT[j+2],
    1, 0)}

它工作正常。但这是非常基本的。例如,如果我想在 100 个连续行上检查 LastPrice > KCT,我需要将条件写下 100 次。不理想。因此我想重写代码以能够指定变量RowsToCheck = X,从而检查X行中的条件,而不必写X次条件.

如果我要在 any 3 个连续行(即使用 OR 运算符)中检查 LastPrice > KCT,而不是在 3 个连续行中(即使用 AND 运算符)。

可以使用 data.table:

简单(而且快速!)
library(data.table)
setDT(df)
df[, check := as.integer(LastPrice > KCT)]
df[, Roll := Reduce('+',shift(check, 0:2L, type = "lead")) >= 3]

只需将 0:2 更改为 0:990:n 以及 >=3 条件,就可以开始了。

编辑: 正如 Frank 指出的那样,您还可以使用:

 df[, Roll := do.call(pmin, shift(check, 0:2, type="lead"))]

我更喜欢这种方法,因为您只需更改一个输入即可改变行数。

我还应该指出,这可以通过将类型参数更改为 "lag"

来扩展到滞后情况

另一种基于 R 的解决方案如下:

check_rows = function(data, n) {
    data$Check = NA
    counter = 0
    for (i in 1:nrow(data)) {
        if (data$LastPrice[i] > data$KCT[i]) {
            counter = counter + 1
            if (counter == n) { # change this to counter >= n if applicable
                data$Check[i] = 1
            }
        } else {
            counter = 0
        }
    }
    data
}

显然不如 data.table 解决方案干净,也不太可能是最好的基础 R 解决方案。

如果性能不是大问题,这也适用于原始问题。

for(j in 1:nrow(df)) {
    df$SignalBinary[j] <- ifelse(all(df$LastPrice[j:(j+n)] > df$KCT[j:(j+n)]), 1, 0)
}

其中n将是要检查的连续行数,如果是OR运算,则将all替换为any

dplyr 包中的另一种方法。

library(zoo)
library(dplyr)
df <- df %>% mutate(SignalBinary = as.integer(rollsum(LastPrice > KCT, n, align = "left", fill = 0) == n))