【问题标题】:Creating a new matrix using vectorization in R在 R 中使用矢量化创建新矩阵
【发布时间】:2021-09-12 19:41:22
【问题描述】:

我有两个矩阵“times”和“scaleFactor”。 “时间”矩阵中的每一行代表一个人,列代表某个事件发生的时间。该事件会更改放大因子,该因子在“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

非常感谢您的帮助。

编辑:我后来意识到“时间”矩阵可以有非整数时间值。对于这种情况,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

【问题讨论】:

  • PraveenKumar,如果您的问题已经得到解答,请选择您喜欢的答案和accept it;这样做不仅为回答者提供了一些积分,而且还为有类似问题的读者提供了一些关闭。尽管您只能接受一个答案,但您可以选择对您认为有帮助的人进行投票。 (如果仍有问题,您可能需要编辑您的问题并提供更多详细信息。)谢谢!

标签: r matrix vectorization


【解决方案1】:

这是replicating 在纯Vectorized 代码中的一种方法

  1. 我们replicate 列序列从 C(减去 1)与 'times' 的length
  2. transposed 'times'上进行比较
  3. 转换为matrix 以创建dim 属性
  4. 应用max.col 获取每行最大值的列索引
  5. 然后,cbind 与行索引
  6. 根据5的行/列索引获取对应的'scaleFactor'值
  7. 使用[] 将输出分配回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

【讨论】:

    【解决方案2】:

    我们可以使用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,它通过scaleFactor 的第一行和我们的第一行“持续时间”(times 不同),第二行与第二行等

    【讨论】:

    • 这种方法在“times”矩阵具有整数值时效果很好。但是,我有一个具有非整数时间值的矩阵。在这种情况下,矩阵 C 没有被正确更新。我不知道如何处理它。谢谢!
    • 您说“每个整数时间点的因子”(并且您的数据是整数),因此假设时间始终是整数似乎是安全的。你能round(.,0)他们来近似你需要的吗?如果没有,那么,你得到了你所问问题的答案,但不是你需要的......我建议你应该用适当的小数 times 更新你的问题,如果你希望得到一些适合你的东西,更新预期输出你的真实需要。
    猜你喜欢
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多