【问题标题】:Filtering NA values when loop goes outside vector (defining loop boundaries)当循环超出向量时过滤 NA 值(定义循环边界)
【发布时间】:2016-04-15 02:51:29
【问题描述】:

我正在运行两个嵌套的 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 NA。那是13个NA。但是有足够的数据只有 4 个 NA。其他 9 个 NA 是我编码不佳的结果。为了解决这个问题,我修改了代码,在给定“j”值的情况下限制“i”的值,从而停止“i”循环以在向量外循环。

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。任何想法将不胜感激!谢谢。

【问题讨论】:

  • 因此,当您说“以下 10 行中的任何一行”时,它更像是“以下最多 10 行中的任何一行(如果行数不足,则更少)...... ” 对吗?因此,当我们到达第 16 行时,您检查第 17 行 > 第 20 行,然后对于第 17 行,NA 是正确的响应,是吗?
  • 没错!这就是我在修改后的代码中尝试的。对于第 18 行,NA 是正确的响应。第 17 行仍然可以计算。
  • 如何计算第17行?在您的示例“对于第 1 行”中,比较从第 2 行 > 第 5 行到第 11 行 > 第 14 行。按照这种逻辑,“对于第 17 行”,我们将所有这些数字加 16,然后从第 18 行 > 第 21 行 不存在 得到——甚至不是第一次比较。请更正示例或评论。
  • 你是对的。我之前的评论是错误的。第 17 到 20 行必须是 NA。谢谢!
  • 最后一个问题。在您的代码中,您检查行之间的差异是否为&gt; 3。但是在您的文本中,您只需说“第 2 行大于第 5 行”。您是否关心第 2 行是否大于第 5 行,或者第 5 行 - 第 2 行 > 3?

标签: r for-loop nested-loops trading


【解决方案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 的挑剔的 cmets 时所做的事情。)

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

我完全放弃了NAs。如果您更愿意拥有它们,请预先分配 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

【讨论】:

  • 确实令人印象深刻。你不知道我多么欣赏这个回应。谢谢!!!
  • 我唯一要补充的是,虽然它可以工作并且相对干净,但它仍然非常低效,因为我们每次需要时都会计算每一行的差异。即第 11 行 - 第 14 行是为第一行计算的,然后再次为第二行计算,再一次...... 10 次。更好的方法是计算所有差异并将它们与min_diff 进行一次比较,将其存储在一个向量中,然后使用该向量计算最终结果。如果这对您的数据来说太慢了,请询问另一个关于如何加快速度的问题,我们可以在那里进行处理。
  • 会做的,非常感谢!窗口很容易有 1500 行,所以我预计它会非常慢。一步一步来。需要先处理并付诸实践。
猜你喜欢
  • 2021-12-29
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
  • 2021-12-01
  • 2023-03-23
  • 1970-01-01
  • 2015-07-23
  • 2016-07-11
相关资源
最近更新 更多