代码之家  ›  专栏  ›  技术社区  ›  Helen

R:应用vs执行调用

  •  7
  • Helen  · 技术社区  · 6 年前

    我刚刚阅读了@david arenburg的简介,发现了一些关于如何培养良好的r编程技能/习惯的有用技巧,其中一个特别打动了我。我一直认为r中的apply函数是处理数据帧的基础,但是他写道:

    如果使用的是data.frames,请忘记有一个名为 申请-无论你做什么-不要使用它。尤其是1分的差距 (此函数的唯一好用法是在矩阵上操作 列-边距为2)。

    一些好的选择:?打电话给我,好吗?PMAX/Pmin?马克斯 ?rowsums/rowmeans/etc,很棒的matrixstats包(用于 矩阵)?Rowsum和更多

    有人能给我解释一下吗?为什么应用功能不受欢迎?

    3 回复  |  直到 6 年前
        1
  •  5
  •   G. Grothendieck    6 年前
    • apply(DF, 1, f) 转换的每行 DF 然后把向量传递给f。 东风 如果是字符串和数字的混合,那么在将行传递给 f 比如说, apply(iris, 1, function(x) sum(x[-5])) 即使吵架也不行 iris[i, -5] 包含所有数字元素。该行已转换为字符串,不能对字符串求和。另一方面 apply(iris[-5], 1, sum) 工作原理与 rowSums(iris[-5]) .

    • 如果 f 生成一个向量结果是一个矩阵而不是另一个数据帧;此外,结果是您可能期望的转置。这个

      apply(BOD, 1, identity)
      

      给予以下而不是给予 BOD 背部:

             [,1] [,2] [,3] [,4] [,5] [,6]
      Time    1.0  2.0    3    4  5.0  7.0
      demand  8.3 10.3   19   16 15.6 19.8
      

      很多年前哈德利·威克汉姆 post iapply 在这个意义上是等幂的 iapply(mat, 1, identity) 收益率 mat ,而不是 t(mat) 在哪里 垫子 是一个矩阵。最近,有了他的plyr软件包,人们可以写下:

      library(plyr)
      ddplyr(BOD, 1, identity)
      

      得到 生化需氧量 作为数据帧返回。

    另一方面 apply(BOD, 1, sum) 将给出与 rowSums(BOD) apply(BOD, 1, f) 可能对函数有用 f 为此 f 生成标量,并且没有类似于 sum / rowSums 案例。也如果 f 产生一个向量,你不介意矩阵结果,你可以转置输出 apply 你自己,尽管很难看,也会有用的。

        2
  •  2
  •   r.user.05apr    6 年前

    我认为作者的意思是,如果可以并且避免应用(因为原则上它是for循环并且需要更长的时间),您应该使用预构建/矢量化函数(因为它更容易):

    library(microbenchmark)
    
    d <- data.frame(a = rnorm(10, 10, 1),
                    b = rnorm(10, 200, 1))
    
    # bad - loop
    microbenchmark(apply(d, 1, function(x) if (x[1] < x[2]) x[1] else x[2]))
    
    # good - vectorized but same result
    microbenchmark(pmin(d[[1]], d[[2]])) # use double brackets!
    
    # edited:
    # -------
    # bad: lapply
    microbenchmark(data.frame(lapply(d, round, 1)))
    
    # good: do.call faster than lapply
    microbenchmark(do.call("round", list(d, digits = 1)))
    
    # --------------
    # Unit: microseconds
    #                                  expr     min    lq     mean  median      uq     max neval
    # do.call("round", list(d, digits = 1)) 104.422 107.1 148.3419 134.767 184.524 332.009   100
    #                            expr     min       lq     mean  median      uq      max neval
    # data.frame(lapply(d, round, 1)) 235.619 243.2055 298.5042 252.353 276.004 1550.265   100
    #
    #                                  expr    min      lq    mean median       uq     max neval
    # do.call("round", list(d, digits = 1)) 96.389 97.5055 113.075 98.175 105.5375 730.954   100
    #                            expr     min       lq     mean  median      uq      max neval
    # data.frame(lapply(d, round, 1)) 235.619 243.2055 298.5042 252.353 276.004 1550.265   100
    
        3
  •  1
  •   Novice    6 年前

    它与r如何存储矩阵和数据帧*有关。如你所知,一个 data.frame 是一个 list 向量,即 数据帧 是一个向量。作为矢量化语言,最好对矢量进行操作,这就是原因。 apply 当margin为2时,不赞成这样做:这样做您就不会处理向量,相反,您将在每次迭代中跨越不同的向量。

    据我所知,使用 应用 使用margin 1与使用 do.call . 尽管后者可能允许更多的使用灵活性。

    *这些信息应该在 manuals .