Применение функции к последовательным подвекторам неравного и переменного размера

Эту проблему лучше всего показать на примере, и она немного отличается от заданного здесь вопроса: Применение функции к последовательным подвекторам одинакового размера

Допустим, у меня есть некоторые данные о ценах для компаний «МММ» и «АВТ», например (даты цен хранятся в именах строк этого фрейма данных):

> a
            MMM  ABT
1991-01-02 11.01 2.58
1991-01-03 10.83 2.48
1991-01-04 10.80 2.43
1991-01-07 10.67 2.39
1991-01-08 10.39 2.42
1991-01-09 10.18 2.42
1991-01-10 10.33 2.43
1991-01-11 10.59 2.44
1991-01-14 10.60 2.38
1991-01-15 10.54 2.39

Во-первых, вероятно, необходимо разбить даты в этом кадре данных на равные интервалы «j». Допустим, j = 2. Вот интервалы, на которые мы будем смотреть:

interval1 is from 1991-01-02 to 1991-01-03
interval2 is from 1991-01-04 to 1991-01-07
interval3 is from 1991-01-08 to 1991-01-09
interval4 is from 1991-01-10 to 1991-01-11
interval5 is from 1991-01-14 to 1991-01-15

Я хочу включить последнее значение, если его там нет, поэтому я использую unique() ниже. Таким образом, предполагая длину интервала «j», мы могли бы использовать их как-то (может быть лучший способ сгенерировать вышеуказанные интервалы):

beg <- rownames(a)[seq(1,nrow(a),2)]
# case for j = 2: 
# [1] "1991-01-02" "1991-01-04" "1991-01-08" "1991-01-10" "1991-01-14"

end <- rownames(a)[seq(1,nrow(a),2)+1]
end <- unique(c(end[!is.na(end)],rownames(a)[nrow(a)]))
# case for j = 2: 
# [1] "1991-01-03" "1991-01-07" "1991-01-09" "1991-01-11" "1991-01-15"

Отсюда у меня есть другой фрейм данных (b), который имеет такие данные:

> b
           portfolio_return
1991-01-09      0.010524144
1991-01-10     -0.010706638
1991-01-11     -0.015665796
1991-01-14     -0.015151515
1991-01-15      0.055000000
1991-01-16     -0.052173913                                                                                                                                                                                                      
1991-01-21     -0.010204082  

То, что я хочу сделать, это найти среднее значение в течение каждого из этих интервалов. Например:

interval1_values = "NA"
interval2_values = "NA"
interval3_values = c(0.010524144)
interval4_values = c(-0.010706638,-0.015665796)
interval5_values = c(-0.015151515, 0.055000000)

#From this we can then easily calculate the average over each interval.

average1 = mean(interval1_values)
average2 = mean(interval2_values)
#etc...

Мое текущее решение выглядит примерно так:

averages_interval <- function(a,b,j){
  # replace 2 with j
  beg <- rownames(a)[seq(1,nrow(a),j)]

  # replace 2 with j
  # replace 1 with j-1
  end <- rownames(a)[seq(1,nrow(a),j)+j-1]
  end <- unique(c(end[!is.na(end)],rownames(a)[nrow(a)]))

  c <- rownames(b)

  tmp <- c()
  j <- 1
  # these loops match our c-vector values in their proper interval
  # for j = 2 case, it places c[1] in interval3, c[2] in interval4, and so on...
  for(i in 1:length(c)){

    while(j <= length(end)){

      if(c[i]>=beg[j] && c[i]<=end[j]){
        tmp <- c(tmp,j)
      }
      j <- j+1
    }
    j <- tmp[length(tmp)]
  }

  df <- data.frame(b,group=tmp)
  df <- df[complete.cases(df),]
  #row_names <- rownames(df)
  # variable needed to store dates if needed later on since we use data.table
  df <- data.table(df)
  averages <- df[,list(mean=mean(portfolio_return)),by=group][[2]]


  return(averages)

}

###### for j = 2
       group        mean
1:     2  0.01052414
2:     3  0.01318622
3:     4  0.01992424

Есть ли более эффективный метод решения этой проблемы?

Спасибо большое.


person road_to_quantdom    schedule 19.11.2014    source источник


Ответы (1)


Ниже вы найдете решение с использованием data.table:

# reading in your data
x <- read.table(text='MMM  ABT
1991-01-02 11.01 2.58
1991-01-03 10.83 2.48
1991-01-04 10.80 2.43
1991-01-07 10.67 2.39
1991-01-08 10.39 2.42
1991-01-09 10.18 2.42
1991-01-10 10.33 2.43
1991-01-11 10.59 2.44
1991-01-14 10.60 2.38
1991-01-15 10.54 2.39', header=TRUE, row.names=1)
#
y <- read.table(text='portfolio_return
1991-01-09      0.010524144
1991-01-10     -0.010706638
1991-01-11     -0.015665796
1991-01-14     -0.015151515
1991-01-15      0.055000000
1991-01-16     -0.052173913                                                                                                                                                                                                      
1991-01-21     -0.010204082', header=TRUE, row.names=1)
# load required packages
require(data.table)
require(zoo)
# setting to data.table
setDT(x, keep.rownames=TRUE)
setDT(y, keep.rownames=TRUE)
# defining the intervals 
# DOUBLE CHECK THIS; I DON'T UNDERSTAND HOW YOU DEFINE THESE
x[, interval := c(1, rep(1:nrow(x), each=2))[1:nrow(x)]] 
# merge data
res <- merge(x, y, by='rn', all = TRUE)
# setting the date as key
res[, rn := as.Date(rn)]
setkey(res, 'rn')
# perhaps carry forward last observation?
# THIS MAY NOT BE WHAT YOU WANT... FEEL FREE TO CHANGE
res[, interval := na.locf(interval)]
# calculate means, start and end of interval
res[, list(start = min(rn), 
           end = max(rn),
           mean_return = mean(portfolio_return)), by=interval]

##    interval      start        end  mean_return
## 1:        1 1991-01-02 1991-01-04           NA
## 2:        2 1991-01-07 1991-01-08           NA
## 3:        3 1991-01-09 1991-01-10 -0.000091247
## 4:        4 1991-01-11 1991-01-14 -0.015408656
## 5:        5 1991-01-15 1991-01-21 -0.002459332
person shadow    schedule 19.11.2014
comment
Благодарность! все, что меня действительно интересует, - это окончательный вектор mean_returns. Есть ли способ сделать это без использования data.frames и хранения всех этих других данных? - person road_to_quantdom; 19.11.2014
comment
также, setDT(x, keep.rownames=TRUE) похоже имеет ошибку - person road_to_quantdom; 19.11.2014