質問

Consider the following (example) zoo object:

example zoo object

The data frame is sorted in ascending order on the date index. The ma3 field provides the 3-day moving average value of the duration field. The comparison field compares the value of the duration value to the corresponding ma3 value; (1) IF duration > ma3 THEN 'ABOVE', (2) IF duration < ma3 THEN 'BELOW', (3) ELSE 'EQUAL'.

The values for the consec_day field are calculated as follows: Starting from the earliest date with a ma3 value if the comparison value equals 'ABOVE' then the sign of the consec_day value is positive, if the comparison value equals 'BELOW' then the sign of the consec_day value is negative, and if the comparison value equals 'EQUAL' then the consec_day value is zero. To determine the magnitude of the consec_day value, count the number of consecutive (from oldest to most recent), identical comparison values.

Questions:

  1. Can the computation of the consec_day field be vectorized?
  2. If so, how?

My current solution uses loops as follows:

    z0 <- zoo(matrix(c(c(345, 432, 112, 332, 496, 414, 211), c(NA, NA, 296.33, 292, 313.33, 414, 373.67), c(NA, NA, 'BELOW', 'ABOVE', 'ABOVE', 'EQUAL', 'BELOW'), c(NA, NA, -1, 1, 2, 0, -1)), nrow = 7, ncol = 4), seq(as.Date('2013-07-31'), as.Date('2013-08-06'), by = "day"))
    colnames(z0) <- c("duration", "ma3", "comparison", "consec_day")
    require(xts)
    for (r in 1:nrow(z0)) {
      if (is.na(z0$comparison[r])) {next}
      if (z0$comparison[r] == 'EQUAL') {z0$consec_day[r] <- 0; next}
      if (is.na(z0$comparison[r - 1])) {z0$consec_day[r] <- ifelse(z0$comparison[r] == 'ABOVE', 1, ifelse(z0$comparison[r] == 'BELOW', -1, 0)); next}
      if ( (xts::coredata(df0)[r, 3] != xts::coredata(df0)[r - 1, 3]) & xts::coredata(df0)[r, 3] == 'ABOVE') {
        df0$consec_day[r] <- 1 
      } else {
      if ( (xts::coredata(df0)[r, 3] != xts::coredata(df0)[r - 1, 3]) & xts::coredata(df0)[r, 3] == 'BELOW') {
        df0$consec_day[r] <- -1 
      } else {ifelse((xts::coredata(df0)[r, 3] != xts::coredata(df0)[r - 1, 3]) & xts::coredata(df0)[r, 3] == 'ABOVE')), df0$consec_day[r] <- df0$consec_day[r - 1] + 1, df0$consec_day[r] <- df0$consec_day[r - 1] - 1}
    }
役に立ちましたか?

解決

Use run length encoding (rle)

You will need to pass an atomic vector (and replace the leading NA values with '.NA' as rle doesn't really deal well with them)

comparison <- z0[,3]
compAtomic <- as.character(comparison)
compAtomic[is.na(compAtomic)] <- '.NA'

# define your changes
changes <- c('BELOW' =-1, 'EQUAL' = 0, 'ABOVE' = 1, '.NA' = NA )
# perform rle (and unclass the results)
rrl <- unclass(rle(compAtomic))
# a bit of `rep` and `sequence`
with(rrl, sequence(lengths) * rep(changes[values],lengths))
#  .NA   .NA BELOW ABOVE ABOVE EQUAL BELOW 
#   NA    NA    -1     1     2     0    -1 
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top