【问题标题】:Apply a function to every row of a matrix or a data frame将函数应用于矩阵或数据框的每一行
【发布时间】:2011-05-13 06:58:05
【问题描述】:

假设我有一个 n×2 矩阵和一个以 2 向量作为其参数之一的函数。我想将该函数应用于矩阵的每一行并获得一个 n 向量。如何在 R 中做到这一点?

例如,我想计算三个点上的二维标准正态分布的密度:

bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
    exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}

out <- rbind(c(1, 2), c(3, 4), c(5, 6))

如何将函数应用到out的每一行?

如何以您指定的方式将除点之外的其他参数的值传递给函数?

【问题讨论】:

    标签: r function matrix apply sapply


    【解决方案1】:

    您只需使用apply() 函数:

    R> M <- matrix(1:6, nrow=3, byrow=TRUE)
    R> M
         [,1] [,2]
    [1,]    1    2
    [2,]    3    4
    [3,]    5    6
    R> apply(M, 1, function(x) 2*x[1]+x[2])
    [1]  4 10 16
    R> 
    

    这需要一个矩阵并对每一行应用一个(愚蠢的)函数。您将额外的参数作为第四个、第五个、... 参数传递给函数apply()

    【讨论】:

    • 谢谢!如果矩阵的行不是函数的第一个参数怎么办?如何指定矩阵的每一行分配给函数的哪个arg?
    • 阅读apply() 的帮助——它按行扫描(当第二个 arg 为 1 时,否则按列),当前行(或 col)始终是第一个参数。这就是事物的定义方式。
    • @Tim :如果您使用内部 R 函数并且该行不是第一个 arg,请按照 Dirk 所做的那样做并制作您自己的自定义函数,其中第 行是 第一个 arg .
    • plyr 包提供了广泛的这些应用类型的功能。它还提供更多功能,包括并行处理。
    • @cryptic0 这个答案迟了,但对于谷歌人来说,apply 中的第二个参数是 MARGIN 参数。这里意味着将函数应用于行(dim(M) 中的第一个维度)。如果是 2,它会将函数应用于列。
    【解决方案2】:

    如果您想应用 sum 或 mean 等常用函数,您应该使用 rowSumsrowMeans,因为它们比 apply(data, 1, sum) 方法更快。否则,请坚持使用apply(data, 1, fun)。您可以在 FUN 参数之后传递其他参数(正如 Dirk 已经建议的那样):

    set.seed(1)
    m <- matrix(round(runif(20, 1, 5)), ncol=4)
    diag(m) <- NA
    m
         [,1] [,2] [,3] [,4]
    [1,]   NA    5    2    3
    [2,]    2   NA    2    4
    [3,]    3    4   NA    5
    [4,]    5    4    3   NA
    [5,]    2    1    4    4
    

    然后你可以这样做:

    apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
        [,1] [,2] [,3] [,4] [,5]
    25%  2.5    2  3.5  3.5 1.75
    50%  3.0    2  4.0  4.0 3.00
    75%  4.0    3  4.5  4.5 4.00
    

    【讨论】:

      【解决方案3】:

      这是一个将函数应用于矩阵的每一行的简短示例。 (这里,应用的函数将每一行归一化为 1。)

      注意:必须使用t()转置来自apply() 的结果,以获得与输入矩阵A 相同的布局。

      A <- matrix(c(
        0, 1, 1, 2,
        0, 0, 1, 3,
        0, 0, 1, 3
      ), nrow = 3, byrow = TRUE)
      
      t(apply(A, 1, function(x) x / sum(x) ))
      

      结果:

           [,1] [,2] [,3] [,4]
      [1,]    0 0.25 0.25 0.50
      [2,]    0 0.00 0.25 0.75
      [3,]    0 0.00 0.25 0.75
      

      【讨论】:

        【解决方案4】:

        第一步是创建函数对象,然后应用它。如果你想要一个具有相同行数的矩阵对象,你可以预先定义它并使用如图所示的 object[] 形式(否则返回的值将被简化为向量):

        bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
             exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
                                   x[2]^2/sigma[2]^2-
                                   2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 
             1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
             }
         out=rbind(c(1,2),c(3,4),c(5,6));
        
         bvout<-matrix(NA, ncol=1, nrow=3)
         bvout[] <-apply(out, 1, bvnormdens)
         bvout
                     [,1]
        [1,] 1.306423e-02
        [2,] 5.931153e-07
        [3,] 9.033134e-15
        

        如果您想使用默认参数以外的参数,则调用应在函数后包含命名参数:

        bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)
        

        apply() 也可以用于高维数组,MARGIN 参数可以是向量也可以是单个整数。

        【讨论】:

          【解决方案5】:

          Apply 做得很好,但速度很慢。 使用 sapply 和 vapply 可能很有用。 dplyr 的 rowwise 也可能有用 让我们看一个如何对任何数据框进行逐行乘积的示例。

          a = data.frame(t(iris[1:10,1:3]))
          vapply(a, prod, 0)
          sapply(a, prod)
          

          请注意,在使用 vapply/sapply/apply 之前分配给变量是一种很好的做法,因为它可以大大减少时间。让我们看看微基准测试结果

          a = data.frame(t(iris[1:10,1:3]))
          b = iris[1:10,1:3]
          microbenchmark::microbenchmark(
              apply(b, 1 , prod),
              vapply(a, prod, 0),
              sapply(a, prod) , 
              apply(iris[1:10,1:3], 1 , prod),
              vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
              sapply(data.frame(t(iris[1:10,1:3])), prod) ,
              b %>%  rowwise() %>%
                  summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
          )
          

          仔细看看 t() 是如何被使用的

          【讨论】:

          • 如果您使用b &lt;- t(iris[1:10, 1:3])apply(b, 2 prod),比较apply 系列可能更公平。
          【解决方案6】:

          如果您想使用数据集的不同部分而不是单个值,另一种方法是使用rollapply(data, width, FUN, ...)。使用宽度向量允许您在数据集的不同窗口上应用函数。我用它来构建一个自适应过滤例程,虽然它不是很有效。

          【讨论】:

            猜你喜欢
            • 2013-02-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-22
            • 1970-01-01
            • 1970-01-01
            • 2011-01-19
            相关资源
            最近更新 更多