如何根据 R 中稀疏矩阵的阈值替换行值?

How to replace row values based on a threshold of a sparse matrix in R?

我有一个相当大的稀疏矩阵 (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 中通常首选对代码进行矢量化。幸运的是,如果我正确理解了你的问题,在这种情况下这很容易做到。

由于您没有提供任何数据(请以后提供),我在下面生成了一个阈值数组thres_array和一个矩阵mat
thres_array 的每个条目与 mat 的整行进行比较是 mat > thres_array 的事情,应用阈值也可以在一行中完成。
通过用 Inf 替换 thres_array 中的零,我们确保 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 ...

我修改了@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.