将函数应用于矩阵或数据框的每一行


129

假设我有一个2乘矩阵和一个将2向量作为其参数之一的函数。我想将函数应用于矩阵的每一行并获取一个n向量。如何在R中执行此操作?

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

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

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

Answers:


180

您只需使用以下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?
蒂姆(Tim)2010年

阅读有关的帮助apply()-它按行扫描(第二个arg为1时,否则为列),并且当前行(或col)始终是第一个参数。这就是事物的定义方式。
Dirk Eddelbuettel

@Tim:如果您使用内部R函数并且该行不是第一个arg,请执行Dirk的操作,并创建自己的自定义函数,其中row 第一个arg。
Joris Meys

3
plyr软件包提供了广泛的这些应用功能。它还提供了更多功能,包括并行处理。
Paul Hiemstra 2011年

6
@ cryptic0这个答案来晚了,但是对于谷歌人来说,apply中的第二个参数是MARGIN参数。此处表示将功能应用于行(中的第一个维度dim(M))。如果为2,则会将函数应用于列。
De Novo

17

如果要应用诸如求和或均值之类的常用函数,则应使用rowSums或,rowMeans因为它们比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

15

这是将函数应用于矩阵的每一行的简短示例。(此处,所应用的函数将每一行标准化为1。)

注意:的结果apply()必须使用进行转置t()以获得与输入矩阵相同的布局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

6

第一步是制作函数对象,然后应用它。如果希望矩阵对象具有相同的行数,则可以对其进行预定义,并使用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参数可以是向量,也可以是单个整数。


4

Apply可以很好地完成工作,但是速度很慢。使用sapply和vapply可能会有用。dplyr的按行排序也可能有用。让我们看一个如何对任何数据帧进行按行乘积的示例。

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 <- t(iris[1:10, 1:3])和,比较申请家庭可能更公平apply(b, 2 prod)
DaSpeeg

2

如果您想使用数据集的不同部分而不是单个值,那么另一种方法是使用rollapply(data, width, FUN, ...)。使用宽度向量可以将函数应用于数据集的变化窗口。我用它来构建自适应过滤例程,尽管它不是很有效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.