使用R中的apply重复相同矩阵的子集化

时间:2016-01-15 09:24:07

标签: r subset apply

动机:我目前正在尝试重新考虑我的编码,例如在可能的情况下排除for循环。使用传统的for循环可以很容易地解决下面的问题,但我想知道R是否有可能利用apply-family来使问题更容易。

问题:我有一个矩阵,比如n x kindex.starts矩阵)和两个起始和终止索引矩阵,称为index.stops和{{1 }}, 分别。它们的大小为n x B,对于某个整数index.stops = index.starts + m,它保持m。每个index.starts[i,j]index.stops[i,j]对需要X作为X[ (index.starts[i,j]:index.stops[i,j]),]。即,他们应该在其索引范围内选择X的所有行。 我可以使用其中一个应用函数来解决这个问题吗?

应用程序 :(对于理解我的问题不一定很重要。)如果您感兴趣,那么在时间序列应用程序中使用块的自举应用程序需要这样做。 X代表原始样本。 index.starts被抽样为replicate(repetitionNumber, sample.int((n-r), ceiling(n/r), replace=TRUE))index.stops被获取为index.stop = index.starts + m。我最终想要的是X行的集合。特别是,我想从repetitionNumber重新采样mr长度为X的块。

示例

#generate data
n<-100 #the size of your sample
B<-5 #the number of columns for index.starts and index.stops
     #and equivalently the number of block bootstraps to sample
k<-2 #the number of variables in X
X<-matrix(rnorm(n*k), nrow=n, ncol = k)

#take a random sample of the indices 1:100 to get index.starts
r<-10 #this is the block length 
#get a sample of the indices 1:(n-r), and get ceiling(n/r) of these 
#(for n=100 and r=10, ceiling(n/r) = n/r = 10). Replicate this B times
index.starts<-replicate(B, sample.int((n-r), ceiling(n/r), replace=TRUE)) 
index.stops<-index.starts + r

#Now can I use apply-functions to extract the r subsequent rows that are 
#paired in index.starts[i,j] and index.stops[i,j] for i = 1,2,...,10 = ceiling(n/r) and 
#j=1,2,3,4,5=B ?

1 个答案:

答案 0 :(得分:1)

这可能比你想要/需要的更复杂,但这是第一种方法。只要评论一下,如果这对您有任何帮助,我很乐意提供帮助。

我的方法使用(多个)* apply-functions。第一个lapply“循环”超过1:B的情况,它首先计算起点和终点,它们被合并到take.rows(带子集数)。接下来,初始矩阵由take.rows(并在列表中返回)进行子集化。作为最后一步,对子集化矩阵的每列采用标准偏差(作为虚函数)。

代码(评论很重)看起来像这样:

# you can use lapply in parallel mode if you want to speed up code...
lapply(1:B, function(i){
  starts <- sample.int((n-r), ceiling(n/r), replace=TRUE)
  # [1] 64 22 84 26 40  7 66 12 25 15
  ends <- starts + r

  take.rows <- Map(":", starts, ends)
#   [[1]]
#   [1] 72 73 74 75 76 77 78 79 80 81 82
#   ...

  res <- lapply(take.rows, function(subs) X[subs, ])
#   res is now a list of 10 with the ten subsets
#   [[1]]
#   [,1]        [,2]
#   [1,]  0.2658915 -0.18265235
#   [2,]  1.7397478  0.66315385
#  ...

  # say you want to compute something (sd in this case) you can do the following
  # but better you do the computing directly in the former "lapply(take.rows...)"
  res2 <- t(sapply(res, function(tmp){
    apply(tmp, 2, sd)
  })) # simplify into a vector/data.frame
#   [,1]      [,2]
#   [1,] 1.2345833 1.0927203
#   [2,] 1.1838110 1.0767433
#   [3,] 0.9808146 1.0522117
#   ...
  return(res2)
})

这是否指向正确的方向/给你答案?