2016-04-15 5 views
0

Я запускаю два вложенных цикла для проверки на каждую строку вектора, если любой из десяти строк ниже - 3 балла больше трех строк ниже. Если true, a 1 записывается во вновь созданный двоичный вектор. (Звучит сложно, я знаю, но сравнения такого рода позволяют проверить условия в временных рядах для торговых целей)Фильтрация значений NA, когда петля выходит за пределы вектора (определение границ цикла)

Например, для строки один, хотят проверить:

  • строка 2> строки 5 + 3 ИЛИ
  • строка 3> строка 6 + 3 ИЛИ

    ...

  • строка 11> строка 14 + 3

(BTW мне нужны петли, идея заключается в том, чтобы запустить это на тысячи строк, а не только 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 НС. Но есть достаточно данных, чтобы иметь только 4 НС. Остальные 9 НС являются результатом плохого кодирования с моей стороны. Чтобы обойти проблему, я модифицировал код, чтобы ограничить значения «i» заданными значениями «j», и, следовательно, остановить цикл «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 НС. Любые идеи были бы высоко оценены! Спасибо.

+0

Так что, когда вы говорите «любой из 10 строки ниже ", это больше похоже на" * любой из десяти строк ниже (меньше, если их недостаточно) .... * «Правильно? Таким образом, к тому времени, когда мы перейдем к строке 16, вы проверите, есть ли строка 17> строка 20, а для строки 17 «NA» - правильный ответ, да? – Gregor

+0

Точно! Вот что я пробовал в модифицированном коде. Для строки 18 NA - правильный ответ. Строка 17 все еще может быть рассчитана. – Krug

+0

Как рассчитывается строка 17? В вашем примере «** Для строки 1 **» сравнения идут из строки 2> строка 5 в строку 11> строка 14. По этой логике «** Для строки 17 **» мы добавляем 16 ко всем этим числа и получить из строки 18> строка 21 *, которая не существует * - даже не первое сравнение. Исправьте либо пример, либо комментарий. – Gregor

ответ

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 - действительно удобная функция для обеспечения того, чтобы мы не выходили за пределы данных. (Эти определения, конечно, должны быть проверены очень тщательно для точности - это то, что я делал, когда я писал эти nitpicky комментариев о том, следует ли или нет семнадцатой запись будет 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 сек цельного LY.Если вы предпочитаете их, предварительно назначьте 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 
+0

Действительно впечатляет. Вы не представляете, насколько я ценю этот ответ. Спасибо!!! – Krug

+0

Единственное, что я хотел бы добавить, это то, что, пока он работает, и он относительно чист, он все еще * ужасно * неэффективен, потому что мы каждый раз вычисляем каждую разницу в каждой строке. Это строка 11 - строка 14 вычисляется для первой строки, затем снова для второй строки и снова ... 10 раз. Лучшим способом было бы рассчитать все различия и сравнить их с «min_diff» один раз, сохранить в векторе, а затем использовать этот вектор для вычисления конечного результата. Если это слишком медленно для ваших данных, задайте еще один вопрос о том, как ускорить его, и мы можем работать над ним. – Gregor

+0

Сделаю, большое спасибо! Окно может легко составлять 1500 строк, поэтому я ожидаю, что оно будет безумно медленным. Один шаг за раз. Необходимо сначала обработать это и применить его на практике. – Krug