将函数应用于矩阵或数据帧的每一行
假设我有一个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
每一行?
如何以指定的方式将除点之外的其他参数的值传递给函数?
您只需使用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()
。
第一步是制作函数对象,然后应用它。如果希望有相同的行数的矩阵对象,可以预定义,并使用对象[]形式所示(否则返回值将被简化为一个向量):
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)
适用()也可以在高维数组使用和MARGIN参数可以是一个矢量,以及一个整数。
如果您想要应用常用函数(如sum或mean),则应该使用rowSums
或rowMeans
,因为它们比apply(data, 1, sum)
方法快。否则,坚持apply(data, 1, fun)
。你可以通过FUN争吵后额外的参数(如德克已经建议):
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
,如果你要使用的数据集的不同部分的另一种方法而不是一个单一的值是使用rollapply(data, width, FUN, ...)
。使用宽度向量允许您在数据集的不同窗口上应用函数。我用它来构建一个自适应过滤例程,虽然它不是非常有效。
下面是将函数应用于矩阵的每一行的简短示例。 (在这里,应用的功能正常化的每一行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
申请做这项工作很好,但速度很慢。 使用sapply和vapply可能会有用。 dplyr的rowwise也可能是有用的 让我们来看看如何做任何数据框的行明智的产品的例子。
a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)
注意,使用vapply/sapply /应用之前分配给变量是很好的做法,因为它减少了很多时间。让我们来看看微基准测试结果
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))
)
有如何吨()正在使用
谢谢你细细品味!如果矩阵的行不是函数的第一个参数呢?如何指定矩阵的每一行分配给函数的哪个arg? – Tim 2010-11-21 04:10:39
阅读'apply()'的帮助 - 它按行进行扫描(当第二个参数是1,否则按列),并且当前行(或列)总是第一个参数。这就是事物的定义。 – 2010-11-21 04:15:46
@Tim:如果您使用内部R函数,并且该行不是第一个参数,请按照Dirk的说法进行操作,并创建您自己的自定义函数,其中第**行是**第一个参数。 – 2010-11-22 12:58:06