当循环超出向量(定义循环边界)时过滤NA值

时间:2016-04-15 02:51:30

标签: r for-loop nested-loops trading

我正在运行两个嵌套的for循环来检查向量的每一行,如果下面的10行中的任何一行是3点,大于3行,则在下面。如果为真,则在新创建的二进制向量上记录1。 (我知道这听起来很复杂,但这种比较允许以交易目的测试时间序列中的条件)

例如,对于第一行,想要检查是否:

  • 第2行>第5 + 3行或
  • 第3行>第6 + 3行或

    ...

  • 第11行>第14 + 3行

(顺便说一句,我需要循环,想法是在数千行上运行,而不仅仅是20行)

以下代码效果很好,但是当其中一个循环超出向量时,它具有产生NA值的不必要特性。

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

df$StrongMoveBinary[j] <- 0
for(j in 1:20) {
  tmp <- 0
  for (i in 1:10) { 
    tmp <- tmp + ifelse (df$LastPrice[j+i] - df$LastPrice[j+i+3] > 3, 1, 0)}
  df$StrongMoveBinary[j] <- tmp>0}

//Note: purpose of tmp variable is to record every occasion that LastPrice > LastPrice 3 rows below, rather than just the last instance

该代码创建 StrongMoveBinary = 1 1 0 0 1 1 1 NA NA NA NA NA NA NA NA NA NA NA NA 。这是13个NAs。但是有足够的数据只有4个NA。其他9个NA是由于我的编码很差。为了解决这个问题,我修改了代码,以限制&#34; i&#34;给出&#34; j&#34;的值,因此停止&#34; i&#34;循环到矢量外循环。

df$StrongMoveBinary[j] <- 0
for(j in 1:20) {
  x <- 0
  if (j <= 10) {x=10}
  if (j > 10) {x=20-j}
  tmp <- 0
  for (i in 1:x) { 
    tmp <- tmp + ifelse (df$LastPrice[j+i] - df$LastPrice[j+i+3] > 3, 1, 0)}
  df$StrongMoveBinary[j] <- tmp>0}

不幸的是它不起作用。 StrongMoveBinary仍然有13个NA。任何想法将不胜感激!谢谢。

1 个答案:

答案 0 :(得分:1)

我认为最大的问题混淆是由于缺少命名变量。你有几个参数(看 3行,如果 10行中的任何一行,数据框中的行数,要检查的差异多少)但是你只是使用全身数字,很难保持直线。你不应该写20,你应该写nrow(df) - 这样,相同的代码可以处理你的20行示例和数千行真实数据。如果任何参数发生变化,您只能在一个地方进行更改。

window = 10     # up to this far below the current row
rows_below = 3  # check against this far down
min_diff = 3    # for a difference at least this big

现在我们将使用这些来显式计算循环的边界。 pmin是一个非常方便的函数,用于确保我们不会超出数据的范围。 (当然,这些定义应该非常仔细地检查以确保准确性 - 这就是我在撰写关于第17个条目是否应该是NA的那些挑剔的评论时我正在做的事情。)

base_rows = 1:(nrow(df) - rows_below - 1)  # can't check more than this

# for a given base row, this is the maximum row to start checking against
candidate_max = pmin(base_rows + window, nrow(df) - rows_below)

# pre-allocate a vector of results
StrongMoveBinary = integer(length = length(base_rows))

完成所有设置后,我们就可以测试了:

for (i in seq_along(base_rows)) {
    StrongMoveBinary[i] = as.numeric(
        any(
            df$LastPrice[(i + 1):candidate_max[i]] - 
                df$LastPrice[((i + 1):candidate_max[i]) + rows_below] > min_diff
        )
    )
}

让我们看看我们得到了什么:

StrongMoveBinary
# [1] 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1

我完全离开了NA。如果您更愿意拥有它们,请预先分配StrongMoveBinary = rep(NA, nrow(df)),而不是我在顶部进行预分配。

最后,也许我们想把它变成一个可以应用于任何矢量的函数。设置参数非常简单。唯一的编辑是使其适用于向量(使用length())而不是数据框的特定行(使用nrow())。

strong_indicate = function(x, window = 10, rows_below = 3, min_diff = 3) {
    base_rows = 1:(length(x) - rows_below - 1)  # can't check more than this

    # for a given base row, this is the maximum row to start checking against
    candidate_max = pmin(base_rows + window, length(x) - rows_below)

    # pre-allocate a vector of results
    StrongMoveBinary = integer(length = length(base_rows))

    for (i in seq_along(base_rows)) {
        StrongMoveBinary[i] = as.numeric(
            any(
                x[(i + 1):candidate_max[i]] - 
                    x[((i + 1):candidate_max[i]) + rows_below] > min_diff
            )
        )
    }
    return(StrongMoveBinary)
}

我们可以在数据栏上调用它:

strong_indicate(x = df$LastPrice)
# [1] 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1

我们可以探索其他值会做什么:

strong_indicate(x = df$LastPrice, min_diff = 12)
# [1] 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1

strong_indicate(x = df$LastPrice, window = 5)
# [1] 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1