我刚刚阅读了@David Arenburg的个人资料,并找到了一些关于如何培养良好的R编程技巧/习惯的有用技巧,尤其令我印象深刻。我一直认为R中的apply函数是使用数据帧的基石,但他写道:
如果您正在使用data.frames,请忘记有一个名为的函数 适用 - 无论你做什么 - 都不要使用它。特别是边际为1 (此功能的唯一好用途是在矩阵上运行 列 - 边缘2)。
一些好的选择:?do.call,?pmax / pmin,?max.col, ?rowSums / rowMeans / etc,令人敬畏的matrixStats包(for matrices),?rowsum等等
有人可以向我解释一下吗?为什么申请职能不受欢迎?
答案 0 :(得分:4)
apply(DF, 1, f)
将DF
的每一行转换为向量,然后将该向量传递给f。如果DF
是字符串和数字的混合,那么该行将被转换为字符向量,然后将其传递给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
很多年前,Hadley Wickham做了post iapply
,在iapply(mat, 1, identity)
返回mat
而不是t(mat)
的意义上是幂等的,mat
是一个矩阵。最近,他的plyr包可以写:
library(plyr)
ddplyr(BOD, 1, identity)
并将BOD
作为数据框返回。
另一方面,apply(BOD, 1, sum)
将提供与rowSums(BOD)
相同的结果,而apply(BOD, 1, f)
可能对f
生成标量的函数f
有用, sum
/ rowSums
案例中没有对应词。此外,如果f
生成一个向量而你不介意矩阵结果,你可以自己调换apply
的输出,虽然很丑,但它会起作用。
答案 1 :(得分:2)
我认为作者的意思是,你应该使用预构建/矢量化函数(因为它更容易),如果可以并且避免应用(因为原则上它是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
答案 2 :(得分:1)
它与R如何存储矩阵和数据帧*有关。您可能知道,data.frame
是list
个向量,也就是说,data.frame
中的每一列都是向量。作为一个矢量化语言,最好对向量进行操作,这就是apply
边缘为2的原因:这样做你不会在向量上工作,相反,你将跨越不同的向量每次迭代。
据我所知,使用边距为1的apply
与使用do.call
没有太大区别。虽然后者可能允许更多的使用灵活性。
*此信息应位于manuals。
中