我有一个包含LastPrice和KCT列的数据框。然后代码创建第三列SignalBinary,并在LastPrice>时将其记录为1。 KCT连续三排。
(例如,在SignalBinary [1]中记录1 LastPrice [1]> KCT [1]和LastPrice [2]> KCT [2]和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)}
工作正常。但这是非常基本的。如果我想检查例如LastPrice&gt; KCT连续100行,我需要写下条件100次。不理想。因此我想重写代码以便能够指定变量RowsToCheck = X,以便检查X行中的条件,而不必将条件写为X次。
如果我要检查LastPrice&gt;,for循环就可以了。 KCT在任何连续3行(即使用OR运算符),而不是连续3行(即使用AND运算符)。
答案 0 :(得分:4)
可以使用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
条件,您就可以了。
编辑:正如弗兰克指出的那样,你也可以使用:
df[, Roll := do.call(pmin, shift(check, 0:2, type="lead"))]
我倾向于喜欢这种方法,因为你只需要在改变行数时改变一个输入。
我还应该指出,通过将类型参数更改为"lag"
答案 1 :(得分:2)
如果表现不是一个大问题,这也可以从最初的问题开始。
for(j in 1:nrow(df)) {
df$SignalBinary[j] <- ifelse(all(df$LastPrice[j:(j+n)] > df$KCT[j:(j+n)]), 1, 0)
}
其中n
将是要检查的连续行数,如果是{操作,则将all
替换为any
。
在dplyr
包中执行此操作的另一种方法。
library(zoo)
library(dplyr)
df <- df %>% mutate(SignalBinary = as.integer(rollsum(LastPrice > KCT, n, align = "left", fill = 0) == n))
答案 2 :(得分:1)
基地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解决方案。