【问题标题】:Apply multiplication on all columns but only for rows that have positive values对所有列应用乘法,但仅适用于具有正值的行
【发布时间】:2020-10-20 20:07:33
【问题描述】:

我有以下矩阵:

 m <- as.matrix(data.frame(a = c(-1,2,3,4),
                b = c(-1,2,2,-4),
                c = c(-1,3,1,-2)))

我想将每一列与向量 v 中的对应值相乘,向量 v 的长度与 m 中的列数相同。我只想将乘法应用于该列中的正值。

v <- c(2,3,-3)

使得 a 列变为 (-1,4,6,8)

我的数据集很大,所以我正在寻找一个优雅的解决方案

【问题讨论】:

    标签: r matrix


    【解决方案1】:
    to_upd <- which(m>0)
    m[to_upd] <- (m * v[col(m)])[to_upd]
    m
    #       a  b  c
    # [1,] -1 -1 -1
    # [2,]  4  6 -9
    # [3,]  6  6 -3
    # [4,]  8 -4 -2
    

    数据

    v <- c(2,3,-3)
    m <- cbind(
      a = c(-1,2,3,4),
      b = c(-1,2,2,-4),
      c = c(-1,3,1,-2)
    )
    

    【讨论】:

      【解决方案2】:

      相乘,然后重置负值:

      # transpose and multiply per row
      res <- t(m) * v
      res <- t(res)
      
      # then reset negatives to original value
      res[m < 0] <- m[ m < 0 ]
      res
      #       a  b  c
      # [1,] -1 -1 -1
      # [2,]  4  6 -9
      # [3,]  6  6 -3
      # [4,]  8 -4 -2
      

      【讨论】:

      • 我应该注意 v 也可以有负值,所以 m 中的正值可以在乘法后变为负数
      • @RobertK 这不是问题,因为我们是从原始矩阵 m 索引的。
      • @RobertK 稍微编辑了解决方案,以匹配您想要乘以行的新数据。
      【解决方案3】:

      你可以这样做:

      m * c(1, v)[col(m) * (m > 0) + 1L]
      #R>       a  b  c
      #R> [1,] -1 -1 -1
      #R> [2,]  4  6 -9
      #R> [3,]  6  6 -3
      #R> [4,]  8 -4 -2
      

      我的数据集很大,所以我正在寻找一个优雅的解决方案

      如果优雅是指快速,那么与其他选项相比,这似乎是一个更快或更快速的解决方案:

      # simulate a larger data set
      set.seed(1)
      n <- 10000
      p <- 50
      m <- matrix(rnorm(n * p), n)
      v <- rnorm(p)
      
      bench::mark(
        sindri_baldur = {
          to_upd <- which(m>0)
          res <- m
          res[to_upd] <- (res * v[col(res)])[to_upd]
          res
        },
        Ben = {
          res <- m
          res * c(1, v)[col(res) * (res > 0) + 1L]
        },
        GKi = {
          i <- m > 0
          res <- m
          res[i] <- (res %*% diag(v))[i]
          res
        },
        zx8754 = {
          res <- t(m) * v
          res <- t(res)
          res[m < 0] <- m[ m < 0 ]
          res
        }, min_time = 2)
      #R> # A tibble: 4 x 13
      #R>   expression         min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time 
      #R>   <bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> 
      #R> 1 sindri_baldur   6.34ms    9.3ms     119.    16.22MB    1.02    235     2      1.97s 
      #R> 2 Ben             5.01ms   5.22ms     190.     9.54MB    0.503   378     1      1.99s 
      #R> 3 GKi            17.82ms  18.28ms      53.8   17.19MB    0.555    97     1       1.8s 
      #R> 4 zx8754          9.03ms   9.26ms     107.    19.07MB    1.53    210     3      1.96s
      

      【讨论】:

        【解决方案4】:

        您可以使用条件m&gt;0 对结果进行子集化:

        i <- m>0
        #i <- which(m>0) #Maybe faster Alternative
        m[i] <- (m %*% diag(v))[i]
        #m[i] <- (m * v[col((m))])[i] #Maybe faster Alternative
        m
        #      a  b  c
        #[1,] -1 -1 -1
        #[2,]  4  6 -9
        #[3,]  6  6 -3
        #[4,]  8 -4 -2
        

        或者另一个可能更快的版本:

        i <- +(m>0)
        m * (v[col(m)]*i + 1 - i)
        

        【讨论】:

          【解决方案5】:

          这是另一个使用 msk 作为掩码的基本 R 选项

          > m*t((msk <- t(m)>0)*v + !msk)
                a  b  c
          [1,] -1 -1 -1
          [2,]  4  6 -9
          [3,]  6  6 -3
          [4,]  8 -4 -2
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-06-12
            • 1970-01-01
            • 2011-03-21
            • 2011-05-26
            • 2019-12-28
            • 2015-02-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多