【问题标题】:R_Extract the row and column of the element in use when using apply functionR_使用apply函数时提取正在使用的元素的行列
【发布时间】:2018-10-05 14:09:57
【问题描述】:

使用apply函数时如何提取正在使用的元素的行列?例如,假设我想为矩阵的每个元素应用一个函数,其中所选元素的行号和列号也是函数中的变量。下面给出了一个简单的可重现示例

mymatrix <- matrix(1:12, nrow=3, ncol=4)

我想要一个执行以下操作的函数

apply(mymatrix, c(1,2), function (x) sum(x, row_number, col_number))

其中row_numbercol_numbermymatrix 中选定元素的行号和列号。请注意,我的函数比sum 更复杂,因此我们很欣赏一个强大的解决方案。

【问题讨论】:

    标签: r apply


    【解决方案1】:

    我不完全确定您要做什么,但我会在此处使用 for 循环。

    预先分配返回matrix,这样会很快

    ret <- mymatrix
    for (i in 1:nrow(mymatrix))
        for (j in 1:ncol(mymatrix))
            ret[i, j] <- sum(mymatrix[i, j], i, j)
    #     [,1] [,2] [,3] [,4]
    #[1,]    3    7   11   15
    #[2,]    5    9   13   17
    #[3,]    7   11   15   19
    

    基准分析 1

    我很好奇,所以我运行了microbenchmark 分析来比较方法;我使用了更大的200x300 矩阵。

    mymatrix <- matrix(1:600, nrow = 200, ncol = 300)
    library(microbenchmark)
    res <- microbenchmark(
        for_loop = {
            ret <- mymatrix
            for (i in 1:nrow(mymatrix))
                for (j in 1:ncol(mymatrix))
                    ret[i, j] <- sum(mymatrix[i, j], i, j)
        },
        expand_grid_mapply = {
            newResult<- mymatrix
            grid1 <- expand.grid(1:nrow(mymatrix),1:ncol(mymatrix))
            newResult[]<-
            mapply(function(row_number, col_number){ sum(mymatrix[row_number, col_number], row_number, col_number) },row_number = grid1$Var1, col_number = grid1$Var2 )
        },
        expand_grid_apply = {
            newResult<- mymatrix
            grid1 <- expand.grid(1:nrow(mymatrix),1:ncol(mymatrix))
            newResult[]<-
            apply(grid1, 1, function(x){ sum(mymatrix[x[1], x[2]], x[1], x[2]) })
        },
        double_sapply = {
            sapply(1:ncol(mymatrix), function (x) sapply(1:nrow(mymatrix), function (y) sum(mymatrix[y,x],x,y)))
        }
    )
    
    res
    #Unit: milliseconds
    #               expr       min        lq      mean    median       uq       max
    #           for_loop  41.42098  52.72281  56.86675  56.38992  59.1444  82.89455
    # expand_grid_mapply 126.98982 161.79123 183.04251 182.80331 196.1476 332.94854
    #  expand_grid_apply 295.73234 354.11661 375.39308 375.39932 391.6888 562.59317
    #      double_sapply  91.80607 111.29787 120.66075 120.37219 126.0292 230.85411
    
    library(ggplot2)
    autoplot(res)
    

    基准分析 2(expand.gridmicrobenchmark 之外)

    grid1 <- expand.grid(1:nrow(mymatrix),1:ncol(mymatrix))
    res <- microbenchmark(
        for_loop = {
            ret <- mymatrix
            for (i in 1:nrow(mymatrix))
                for (j in 1:ncol(mymatrix))
                    ret[i, j] <- sum(mymatrix[i, j], i, j)
        },
        expand_grid_mapply = {
            newResult<- mymatrix
            newResult[]<-
            mapply(function(row_number, col_number){ sum(mymatrix[row_number, col_number], row_number, col_number) },row_number = grid1$Var1, col_number = grid1$Var2 )
        },
        expand_grid_apply = {
            newResult<- mymatrix
            newResult[]<-
            apply(grid1, 1, function(x){ sum(mymatrix[x[1], x[2]], x[1], x[2]) })
        }
    )
    
    res
    #Unit: milliseconds
    #               expr       min        lq      mean    median        uq      max
    #           for_loop  39.65599  54.52077  60.87034  59.19354  66.64983  95.7890
    # expand_grid_mapply 130.33573 167.68201 194.39764 186.82411 209.33490 400.9273
    #  expand_grid_apply 296.51983 373.41923 405.19549 403.36825 427.41728 597.6937
    

    【讨论】:

    • 我认为这种方法对于初学者来说要清晰得多。
    • @AndreElrico 也许,我也先选择了mapply/Map 方法;-) 我很好奇两者会如何比较,所以添加了microbenchmark 比较。
    • 感谢基准测试,我学到了一些东西。如果 expand.grid 超出基准,我会很好奇它的样子。
    • 双 for 循环。 2018 年仍是一件事
    • @MaMu 是的,老实说,我不太清楚为什么会这样。起初我认为这可能是因为在double_sapply 中,您首先遍历列然后遍历行,而在for 循环中,我首先遍历行然后遍历列。但即使交换订单也不会真正改变结果。一定是sapply带来的开销,也许是隐含的simplify = TRUE
    【解决方案2】:

    这不是 apply 的工作方式:您无法从 [lsvm]?apply-family 内部访问当前索引(行、列索引)。

    您必须在申请前创建当前行和列索引。 ?expand.grid.

    mymatrix <- matrix(1:12, nrow=3, ncol=4)
    newResult<- mymatrix
    
    grid1 <- expand.grid(1:nrow(mymatrix),1:ncol(mymatrix))
    
    newResult[]<-
    mapply(function(row_number, col_number){ sum(mymatrix[row_number, col_number], row_number, col_number) },row_number = grid1$Var1, col_number = grid1$Var2 )
    
    newResult
    
    #     [,1] [,2] [,3] [,4]
    #[1,]    3    7   11   15
    #[2,]    5    9   13   17
    #[3,]    7   11   15   19
    

    如果你想使用apply

    newResult[]<-    
    apply(grid1, 1, function(x){ sum(mymatrix[x[1], x[2]], x[1], x[2]) })
    

    【讨论】:

      【解决方案3】:

      这是我对outer() 函数的想法。

      第三个参数FUN 可以是任何两个参数的函数。

      mymatrix <- matrix(1:12, nrow = 3, ncol = 4)
      nr <- nrow(mymatrix)
      nc <- ncol(mymatrix)
      mymatrix + outer(1:nr, 1:nc, FUN = "+")
      
           [,1] [,2] [,3] [,4]
      [1,]    3    7   11   15
      [2,]    5    9   13   17
      [3,]    7   11   15   19
      

      使用@Maurits Evers 的基准代码:

      Unit: microseconds
           expr       min         lq      mean    median        uq        max
       for_loop 19963.203 22427.1630 25308.168 23811.855 25017.031 158341.678
          outer   848.247   949.3515  1054.944  1011.457  1059.217   1463.956
      

      另外,我尝试用apply(X, c(1,2), function (x)) 来完成你最初的想法:

      (比其他答案慢一点)

      mymatrix <- matrix(1:12, nrow = 3, ncol = 4)
      n <- 1                                        # n = index of data
      nr <- nrow(mymatrix)
      apply(mymatrix, c(1,2), function (x) {
        row_number <- (n-1) %% nr + 1               # convert n to row number
        col_number <- (n-1) %/% nr + 1              # convert n to column number
        res <- sum(x, row_number, col_number)
        n <<- n + 1
        return(res)
      })
      
           [,1] [,2] [,3] [,4]
      [1,]    3    7   11   15
      [2,]    5    9   13   17
      [3,]    7   11   15   19
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-07-01
        • 2014-01-16
        • 2022-06-13
        • 2017-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多