如何基于R中的稀疏矩阵的阈值替换行值?

问题描述 投票:0回答:2

我有一个很大的稀疏矩阵(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循环,但我想不出一种可持续的方法。

r optimization sparse-matrix memory-efficient
2个回答
1
投票

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

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

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


0
投票

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

由于您尚未提供任何数据(请将来提供),因此我在下面生成了阈值数组thres_array和矩阵mat。那么,将thres_array的每个条目与mat的整个行进行比较就成了mat > thres_array的事,并且阈值的应用也可以一行完成。通过用thres_arrayInf替换零,我们确保mat > 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 ...
© www.soinside.com 2019 - 2024. All rights reserved.