检查多行中是否存在条件
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:99
或 0: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))
我有一个包含 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:99
或 0: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))