Изменить значение некоторого столбца в xts на основе значений других столбцов с помощью обратного просмотра - PullRequest
2 голосов
/ 27 февраля 2011

У меня есть следующий объект xts (представляющий длинные / короткие записи (столбцы 1 и 2) и триггеры выхода (столбцы 3 и 4) с «совокупным» столбцом сигнала, который должен быть 1 (система длинная), -1 (система длинная)является коротким) или 0 (система плоская). Я не могу сделать эту работу для "совокупного" сигнала столбца5 ...

Данные:

         LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93               0                0              1               0      0
19.02.93               0                0              0               1      0
22.02.93               1                0              0               0      1
23.02.93               0                0              0               0      0
24.02.93               0                0              0               0      0
25.02.93               0                0              0               0      0
26.02.93               0                0              1               0      0
01.03.93               0                0              1               0      0
04.03.93               0                1              0               0     -1
05.03.93               0                0              0               0      0
11.03.93               0                0              0               1      0
12.03.93               0                0              1               0      0

Я хотел бы преобразоватьданные в этой форме:

         LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93               0                0              1               0      0
19.02.93               0                0              0               1      0
22.02.93               1                0              0               0      1
23.02.93               0                0              0               0      1
24.02.93               0                0              0               0      1
25.02.93               0                0              0               0      1
26.02.93               0                0              1               0      1
01.03.93               0                0              1               0      0
04.03.93               0                1              0               0     -1
05.03.93               0                0              0               0     -1
11.03.93               0                0              0               1     -1
12.03.93               0                0              1               0      0

Я попытался обновить программу, как показано ниже (но id не работает; закомментированная часть также не работает и работает очень медленно - я знаю об использовании циклов в Rмедленно, но это была единственная идея, которая у меня была):

padMinusPlusOnes<-function(signals, longEntryColumn=1, shortEntryColumn=2, signalsColumn=5) {   
    ret<-signals
#get all indexes between long entry equals 1 to long exit equals 1 and set signalsColumn for these rows to 1
    ret[(lag(ret)[, longEntryColumn] == 1) & (ret[, signalsColumn] == 0), signalsColumn]<-1
#get all indexes between short entry equals 1 to short exit equals 1 and set signalsColumn for these rows to -1
    ret[(lag(ret)[, shortEntryColumn] == -1) & (ret[, signalsColumn] == 0), signalsColumn]<--1

    return(ret)

#   ret<-signals
#   for (i in 2:NROW(ret)) {
#       if ((ret[i - 1, longEntryColumn] == 1) & (ret[, signalsColumn] == 0)) {
#           ret[i, signalsColumn]<-1
#       }
#       if ((ret[i - 1, shortEntryColumn] == -1) & (ret[, signalsColumn] == 0)) {
#           ret[i, signalsColumn]<--1
#       }
#   }
#   
#   return(ret)
}

Спасибо за вашу любезную помощь в преобразовании данных.

С уважением, Само.

Редактировать примечание: получив два очень полезных и проницательных ответа от Прасада Чаласани и Дж. Винчестера, я понял, что пропустил важную информацию о том, как структурированы мои данные. Поэтому я изменил данные выше, чтобы лучше отражать свои данные, и скопировал оригинал (наich два ответа были основаны) ниже:

Данные:

         LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93               0                0              0               0      0
19.02.93               0                0              0               0      0
22.02.93               1                0              0               0      1
23.02.93               0                0              0               0      0
24.02.93               0                0              0               0      0
25.02.93               0                0              0               0      0
26.02.93               0                0              1               0      0
01.03.93               0                0              0               0      0
04.03.93               0                1              0               0     -1
05.03.93               0                0              0               0      0
11.03.93               0                0              0               1      0
12.03.93               0                0              0               0      0

Я хотел бы преобразовать данные в эту форму:

         LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93               0                0              0               0      0
19.02.93               0                0              0               0      0
22.02.93               1                0              0               0      1
23.02.93               0                0              0               0      1
24.02.93               0                0              0               0      1
25.02.93               0                0              0               0      1
26.02.93               0                0              1               0      1
01.03.93               0                0              0               0      0
04.03.93               0                1              0               0     -1
05.03.93               0                0              0               0     -1
11.03.93               0                0              0               1     -1
12.03.93               0                0              0               0      0

Ответы [ 3 ]

4 голосов
/ 28 февраля 2011

Вам не нужно использовать петли, и вам не нужно «оглядываться назад». Вы можете использовать векторизованную функцию cumsum, чтобы получить то, что вы хотите. Предполагая, что ваши длинные периоды входа / выхода и короткие периоды входа / выхода не перекрываются, вы можете сделать это: Сначала создайте фиктивные сигналы:

n <- 15
zeros <- rep(0,n)
LongEnt <- replace(zeros, c(1, 12), 1)
LongEx <- replace(zeros, c(4, 14), 1)
ShortEnt <- replace(zeros, 6, 1)
ShortEx <- replace(zeros, 10, 1)

Теперь сделайте магию cumsum, чтобы получить правильный «совокупный» столбец сигнала:

SigLong <- cumsum(LongEnt) - cumsum(LongEx) + LongEx
SigShort <- -cumsum(ShortEnt) + cumsum(ShortEx) - ShortEx
> cbind(LongEnt, LongEx, ShortEnt, ShortEx, Signal = SigLong + SigShort)
      LongEnt LongEx ShortEnt ShortEx Signal
 [1,]       1      0        0       0      1
 [2,]       0      0        0       0      1
 [3,]       0      0        0       0      1
 [4,]       0      1        0       0      1
 [5,]       0      0        0       0      0
 [6,]       0      0        1       0     -1
 [7,]       0      0        0       0     -1
 [8,]       0      0        0       0     -1
 [9,]       0      0        0       0     -1
[10,]       0      0        0       1     -1
[11,]       0      0        0       0      0
[12,]       1      0        0       0      1
[13,]       0      0        0       0      1
[14,]       0      1        0       0      1
[15,]       0      0        0       0      0

Обновление . В соответствии с измененным вопросом ОП нам нужно обработать случай произвольной последовательности сигналов входа / выхода и найти периоды между первой записью и соответствующим первым выходом. Вот способ сделать это с очень простыми арифметическими операциями (то есть без дорогих обратных проверок или проверки if / else). Нам просто нужна небольшая модификация функции cumsum, которую я назову cumplus - это похоже на cumsum, за исключением того, что после взятия каждой суммы она заменяет ее на 1 или 0 в зависимости от того, положительна она или нет:

cumplus <- function(y) Reduce(function(a,b) a + b > 0, y, 0, accum=TRUE)[-1]

(Кстати, Reduce - это хороший способ компактно определить накопительную функцию без явного выписывания цикла for - подробности см. ?Reduce).

Теперь возьмем пример сигналов входа / выхода:

LongEnt <- c(1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 
0, 1, 0, 0)
LongEx <- c(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 
1, 0, 0, 1)

x <- LongEnt - LongEx  
z <- cumplus(x)

Это почти то, что мы хотим ... нам просто нужно вставить 1 в конце каждого блока единиц.

z <- z - c(0,pmin(0,diff(z)))

> cbind(LongEnt, LongEx, signal = z)
      LongEnt LongEx signal
 [1,]       1      0      1
 [2,]       0      0      1
 [3,]       0      0      1
 [4,]       1      0      1
 [5,]       0      0      1
 [6,]       0      0      1
 [7,]       1      0      1
 [8,]       0      0      1
 [9,]       0      1      1
[10,]       0      0      0
[11,]       0      0      0
[12,]       0      1      0
[13,]       1      0      1
[14,]       0      0      1
[15,]       0      0      1
[16,]       1      0      1
[17,]       0      0      1
[18,]       0      0      1
[19,]       0      1      1
[20,]       0      0      0
[21,]       0      1      0
[22,]       1      0      1
[23,]       0      0      1
[24,]       0      1      1

Работа с короткими входами / выходами, конечно, будет аналогичной.

0 голосов
/ 28 февраля 2011

Я уверен, что есть «волшебный» (то есть векторизованный) способ сделать это, но сейчас вот работоспособное решение для петель.

# your example data
sigmat <- structure(list(
  date = structure(c(6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L), 
  .Label = c("01.03.93", "04.03.93", "05.03.93", "11.03.93", "12.03.93", 
    "18.02.93", "19.02.93", "22.02.93", "23.02.93", "24.02.93", 
    "25.02.93", "26.02.93"), class = "factor"), 
  LongEntrySignal = c(0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), 
  ShortEntrySignal = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L), 
  LongExitSignal = c(1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L), 
  ShortExitSignal = c(0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L), 
  Signal = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), 
  .Names = c("date", "LongEntrySignal", "ShortEntrySignal", 
    "LongExitSignal", "ShortExitSignal", "Signal"), 
  row.names = c(NA, -12L), class = "data.frame")

# if there is an entry/exit signal, turn on/off
# otherwise keep the same state as the day before
sigShort <- sigmat$ShortEntrySignal - sigmat$ShortExitSignal
sigLong  <- sigmat$LongEntrySignal -  sigmat$LongExitSignal
for(i in 2:nrow(sigmat)) {
  if(sigShort[i] == 0) sigShort[i] <- sigShort[i-1]
  if(sigLong[i]  == 0) sigLong[i]  <- sigLong[i-1]
}

# The entry signal stays "on" until end of the exit day 
# so extend the on sequences by one day, and shorten the off sequences
sigRLE <- rle((sigLong > 0) * 1 - (sigShort > 0) * 1)
sigRLE$lengths[-1] <- sigRLE$lengths[-1] + 1:0 + 0:-1
sigmat$Signal <- rep(sigRLE$values, sigRLE$lengths)
0 голосов
/ 28 февраля 2011

Я сделал пару логических предположений, а именно: система запускается в нейтральном состоянии (т. Е. В ноль); если система покидает «нулевое состояние» сигналом «входа» любого типа (длинный / короткий), следующий сигнал должен быть сигналом «выхода» того же типа. Если я прочитаю ваши данные в матрицу с именем sigmat, я могу сделать следующее.

streamLong <- with(sigmat, LongEntrySignal == 1 | LongExitSignal == 1)
switches <- which(streamLong)
mat <- cbind(c(1, switches), c(switches, length(streamLong) + 1), 0:1)
stateLong <- do.call("c", apply(mat, 1, function(ro)rep(ro[3], ro[2] - ro[1])))

streamShort <- with(sigmat, ShortEntrySignal == 1 | ShortExitSignal == 1)
switches <- which(streamShort)
mat <- cbind(c(1, switches), c(switches, length(streamShort) + 1), 0:1)
stateShort <- do.call("c", apply(mat, 1, function(ro)rep(ro[3], ro[2] - ro[1])))

# EDIT: The entry signal stays "on" until end of the exit day 
# so add one to the on sequences, and subtract one from the off sequences
sigRLE <- rle(stateLong - stateShort)
sigRLE$lengths[-1] <- sigRLE$lengths[-1] + 1:0 + 0:-1
sigmat$signal <- rep(sigRLE$values, sigRLE$lengths)

Вот вывод.

R> sigmat
       date LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal signal
1  18.02.93               0                0              0               0      0      0
2  19.02.93               0                0              0               0      0      0
3  22.02.93               1                0              0               0      1      1
4  23.02.93               0                0              0               0      0      1
5  24.02.93               0                0              0               0      0      1
6  25.02.93               0                0              0               0      0      1
7  26.02.93               0                0              1               0      0      1
8  01.03.93               0                0              0               0      0      0
9  04.03.93               0                1              0               0     -1     -1
10 05.03.93               0                0              0               0      0     -1
11 11.03.93               0                0              0               1      0     -1
12 12.03.93               0                0              0               0      0      0
...