【问题标题】:How to replace row values based on a threshold of a sparse matrix in R?如何根据 R 中稀疏矩阵的阈值替换行值?
【发布时间】:2020-09-22 22:42:13
【问题描述】:

我有一个非常大的稀疏矩阵(40,000 x 100,000+),如果某个元素大于某个阈值,我想用 1 替换它。但是,矩阵中的每一行都有一个唯一的阈值(这只是一个向量,它是行的长度)所以我想逐行检查特定行的元素是否大于唯一阈值为那一行。

我最初通过遍历稀疏矩阵的所有非零元素来尝试使用 for 循环解决此问题,但这花费了太长时间,因为我有超过 1 亿个元素要遍历。

number_of_elem <- matrix@x %>% length()
for (j in 1:number_of_elem){

  threshold <- thres_array[j] 

  if (threshold == 0){
    next
  }

  if (matrix@x[j] > threshold){

    matrix@x[j] <- 1

  }

}

然后我开始尝试使用 apply 函数,但我无法准确解决如果阈值为零时跳过阈值的问题。作为参考,我首先计算了每一行的分位数,并将我的阈值设置为高于第 95 个百分位数。由于它是一个稀疏矩阵,因此某些阈值为零。

关于如何解决这个问题的任何想法?根据我在 R 中的了解,最好将代码矢量化并避免 for 循环,但我想不出一种可持续的方法。

【问题讨论】:

  • 什么是class(matrix)?
  • > class(matrix) [1] "dgCMatrix" attr(,"package") [1] "Matrix"

标签: r optimization sparse-matrix memory-efficient


【解决方案1】:

我修改了@Bas 解决方案,以便它利用矩阵的稀疏性来提高性能。

mat@x[mat@x > thres_array[mat@i + 1] ] <- 1

mat@x 给出稀疏矩阵的非零元素,mat@i 给出非零元素所属的行(你必须加 1,因为它是零索引的)。由于thres_array 的元素基于相应的行,您可以从mat@x &gt; thres_array[mat@i + 1] 创建一个逻辑向量并将这些值重新分配给1。

【讨论】:

    【解决方案2】:

    你说得对,在 R 中,通常更喜欢矢量化你的代码。幸运的是,如果我正确理解了您的问题,在这种情况下可以轻松完成。

    由于您没有提供任何数据(请在以后提供),我在下面生成了一个阈值数组thres_array和一个矩阵mat。
    将thres_array 的每个条目与mat 的整行进行比较是mat &gt; thres_array 的问题,并且应用阈值也可以在一行中完成。
    通过用Inf 替换thres_array 中的零,我们确保mat &gt; thres_array 永远不会为真,因此会跳过这些值。

    thres_array <- 0:9
    mat <- matrix(runif(1000, max = 10), nrow = 10)
    
    # get rid of zeros
    thres_array[thres_array == 0] <- Inf
    
    # apply threshold
    mat[mat > thres_array] <- 1
    

    对于我随机生成的矩阵mat,这给出了以下内容。

               [,1]     [,2]      [,3]      [,4]     [,5]      [,6]     [,7]       [,8]     [,9]     [,10]    [,11]    [,12]     [,13]    [,14]
     [1,] 8.80034895 8.422070 4.9415068 5.0451436 2.038524 0.1091817 7.900194 4.22983010 1.318235 3.9218194 7.491424 1.414268 8.9569142 3.347458
     [2,] 1.00000000 1.000000 1.0000000 1.0000000 0.654243 1.0000000 1.000000 1.00000000 1.000000 1.0000000 1.000000 1.000000 1.0000000 1.000000
     [3,] 1.00000000 1.000000 1.2302859 1.0000000 1.000000 0.9299740 1.000000 1.00000000 1.661907 1.0000000 1.000000 1.293784 1.0000000 1.987043
     [4,] 1.01573038 1.566547 1.0000000 1.0000000 2.469330 1.0000000 0.609428 2.04922439 1.000000 1.0000000 1.000000 1.000000 1.0000000 1.000000
     [5,] 1.00000000 1.000000 0.2595911 1.0000000 1.000000 3.0623223 1.000000 1.00000000 3.333816 0.7444644 1.000000 1.253450 2.6955623 1.000000
     [6,] 3.66609571 1.000000 2.0263511 2.5939923 1.000000 1.0000000 1.536697 0.41910933 3.586519 1.0000000 1.000000 4.921295 1.7967002 1.000000
     [7,] 1.00000000 1.000000 ...
    

    【讨论】:

    • 您提出的方法在理论上可行,但由于矩阵较大,我一直遇到内存问题。我想知道是否有办法利用稀疏矩阵的槽特征。就像 mat@x 给出非零值和 mat@i 给出非零元素所属行的索引一样。
    • 好的,明白了。很抱歉没有把它捡起来。不幸的是,我对 R 中的稀疏矩阵一无所知。我将留下这个答案,也许其他人将来可能会从中受益。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2013-06-26
    • 1970-01-01
    • 2017-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多