在 R 中使用矢量化创建新矩阵

Creating a new matrix using vectorization in R

我有两个矩阵 'times' 和 'scaleFactor'。 'times' 矩阵中的每一行代表一个人,该列代表某个事件发生的时间。该事件会更改放大系数,可在 'scaleFactor' 矩阵中找到。例如,对于第 1 个人,时间间隔 (1,3).

中的因子为 1.2

我想创建一个在每个整数时间点都有因子的矩阵 C,其中第一列是时间 = 0。我写了生成矩阵'C'的代码,但我想知道是否可以避免'for'循环,因为实际矩阵非常大

scaleFactor <-  matrix(c(1,1.1,1.2,1.4,
                         1,1.3,1.4,1.6,
                         1,1.2,1.6,2.1),nrow = 3,ncol = 4, byrow = T)

times <- matrix(c(0,1,3,99,
              0,2,5,99,
              0,1,4,99),nrow = 3,ncol = 4,byrow = T)

> scaleFactor
     [,1] [,2] [,3] [,4]
[1,]    1  1.1  1.2  1.4
[2,]    1  1.3  1.4  1.6
[3,]    1  1.2  1.6  2.1
> times
     [,1] [,2] [,3] [,4]
[1,]    0    1    3   99
[2,]    0    2    5   99
[3,]    0    1    4   99

C <-  matrix(0,nrow = 3,ncol = 6)

for (i in 1:ncol(C)){
  indices <- max.col(i-1<=times,'first') 
  C[,i] <- scaleFactor[cbind(1:3,indices)]
}

> C
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1  1.1  1.2  1.2  1.4  1.4
[2,]    1  1.3  1.3  1.4  1.4  1.4
[3,]    1  1.2  1.6  1.6  1.6  2.1

非常感谢您的帮助。

编辑:我后来意识到 'times' 矩阵可以有非整数时间值。对于这种情况,akrun 建议的方法有效。谢谢!

times2 <- matrix(c(0,1.2,3.6,99,
                  0,2.1,5.3,99,
                  0,1,4,99),nrow = 3,ncol = 4,byrow = T)

> times2
     [,1] [,2] [,3] [,4]
[1,]    0  1.2  3.6   99
[2,]    0  2.1  5.3   99
[3,]    0  1.0  4.0   99

# Matrix C would be -
> C
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1  1.1  1.2  1.2  1.4  1.4
[2,]    1  1.3  1.3  1.4  1.4  1.4
[3,]    1  1.2  1.6  1.6  1.6  2.1

这是 rep在纯 Vectorized 代码中拼接的一种方法

  1. 我们rep将C(减去1)的列序列与'times'
  2. length联系起来
  3. transposed 'times'
  4. 进行比较
  5. 转换为 matrix 以创建 dim 属性
  6. 应用max.col获取每行最大值的列索引
  7. 然后,cbind 与行索引
  8. 从5
  9. 根据row/column索引得到对应的'scaleFactor'值
  10. 使用 [] 将输出分配回 C,以便保留矩阵属性
C[] <- scaleFactor[cbind(1:3, max.col(matrix(rep(seq_len(ncol(C)) - 1,
     each = length(times)) <= c(t(times)), ncol = ncol(times), 
      byrow = TRUE), "first"))]

-输出

C
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1  1.1  1.2  1.2  1.4  1.4
[2,]    1  1.3  1.3  1.4  1.4  1.4
[3,]    1  1.2  1.6  1.6  1.6  2.1

我们可以使用 repasplit 的技巧(将数组拆分为向量列表,在这里很方便)。

C <- t(
  mapply(rep, asplit(scaleFactor,1),
         times = asplit(cbind(1, t(apply(times, 1, diff))), 1))
)
dim(C)
# [1]   3 100
C[,1:8]
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# [1,]    1  1.1  1.2  1.2  1.4  1.4  1.4  1.4
# [2,]    1  1.3  1.3  1.4  1.4  1.4  1.6  1.6
# [3,]    1  1.2  1.6  1.6  1.6  2.1  2.1  2.1

它的稳定性取决于times的最后一列是否相等(这样所有的人迭代相同的时间段数)。

首先将 times(发生变化的时间段)转换为“持续时间”(每列中的天数),

cbind(1, t(apply(times, 1, diff)))
#      [,1] [,2] [,3] [,4]
# [1,]    1    1    2   96
# [2,]    1    2    3   94
# [3,]    1    1    3   95

从那里,我们使用这些数字作为 reptimes= 参数。为了保持维度正确,我们为每个人独立地做这件事,这就是为什么我们需要使用 asplit(., 1):

按行拆分矩阵
asplit(scaleFactor, 1)
# [[1]]
# [1] 1.0 1.1 1.2 1.4
# [[2]]
# [1] 1.0 1.3 1.4 1.6
# [[3]]
# [1] 1.0 1.2 1.6 2.1

然后我们将比例因子与相应的时间配对成rep:

head(
  rep(c(1, 1.1, 1.2, 1.4), times = c(1, 1, 2, 96)),
  8)
# [1] 1.0 1.1 1.2 1.2 1.4 1.4 1.4 1.4

为了同时有效地遍历两个矩阵的所有行,我们 asplit 矩阵并将它们输入 mapply,它传递了 [=24= 的第一行] 与我们的“持续时间”的第一行(times 不同),第二行与第二行等