R: 矩阵运算及常用函数 III - *apply Part I
来源:互联网 发布:手机视频制作软件 编辑:程序博客网 时间:2024/06/06 08:29
在”矩阵运算及常用函数I“里已经提到过,apply系列函数“主要用于某维度上某函数/方法的批量应用”,可以避免“控制流循环带来的高错误率以及漫长的响应时间”。
为了比较响应时间,我们可以先做一个简单的测试:为一列数据做一一系列幂的变形,依据指数的sequence,生成一系列的新数据。然后用system.time()来测试运行的时间(如何解读system.time()结果)。
test1. for循环
> power1 <- function(var = EuStockMarkets[,1]){
+ new.var <- NULL
+ for(i in seq(.001, .999, .001)){
+ if(is.null(new.var)){
+ new.var <- var^i
+ }else{
+ new.var <- data.frame(new.var, var^i)
+ }
+ }
+ return(new.var)
+ }
+ new.var <- NULL
+ for(i in seq(.001, .999, .001)){
+ if(is.null(new.var)){
+ new.var <- var^i
+ }else{
+ new.var <- data.frame(new.var, var^i)
+ }
+ }
+ return(new.var)
+ }
> system.time(power1())
user system elapsed
1.06 0.00 1.08
这里elapsed说明调用和运行程序到整体执行完一共花费的时间,这段循环的function花费了1.08秒
test2. sapply
> power2<-function(i)EuStockMarkets[,1]^i
> system.time(sapply(seq(.001,.999,.001),power2))
user system elapsed
0.42 0.00 0.42
0.42 0.00 0.42
这个地方, 当我们使用sapply进行处理的时候,总共消耗了0.42秒,比for循环快了一倍多,虽然只快了不到一秒,但是执行效率有相当大幅度的提升。当处理的维度变得原来越多的时候(比如for的循环嵌套),apply函数的优势就会更明显。
-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-
在help system中搜索apply
> ??apply
可以看到在{base}中自带的跟apply相关的函数有7个:
base::applyApply Functions Over Array Marginsbase::byApply a Function to a Data Frame Split by Factorsbase::eapplyApply a Function Over Values in an Environmentbase::lapplyApply a Function over a List or Vectorbase::mapplyApply a Function to Multiple List or Vector Argumentsbase::rapplyRecursively Apply a Function to a Listbase::tapplyApply a Function Over a Ragged Array其中,lapply下还有不同形式的函数: sapply, vapply, replicate, simplify2array。这样一来,*apply一族里一共有11个可用函数。接下来我们打乱顺序学习。
-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-
1. apply(X, MARGIN, FUN, ...)
对数组按指定维度以指定函数进行计算。
参数:
X: 一个数组,包括矩阵。
MARGIN: 可以是单一的数字,也可以是一个vector指定X的维度,同样,也可以是包含dimension names的字符向量。在一个2维数组中,1代表行,2代表列,c(1,2)则是同时应用FUN到行和列上。
FUN: 将要被应用的函数。
...: 如果FUN需要明确一些参数,则把参数转移到...处。
> apply(mtcars, 2, mean)[1:5] 'calculate the column mean
mpg cyl disp hp drat
20.090625 6.187500 230.721875 146.687500 3.596563
当然以上效果也可以直接通过colMeans(mtcars)来实现,这里只是提供一个使用思路。
当数组只有2维时,MARGIN = c(1,2)对部分函数来说是无效的,如apply(mtcars, c(1,2), mean)得到的还是mtcars这个数组本身。但是维度达到3以上,MARGIN就会又更明显的作用。
> z <- array(1:24, dim = 2:4)
> zseq <- apply(z, 1:2, max)
> zseq
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
---------------------------------------------------------------------------------
2. tapply(X, INDEX, FUN = NULL, ..., simplify =T)
对基本因子进行分组统计
参数:
X: 基本对象。如vector或factor。
INDEX: 包含一个或多个factor的list,每个factor的长度都应该同X相当。INDEX用于将X归类。
simplify: 如果simplify = F, 则所有返回的结果均以list形式呈现,T表示简化返回的结果。
> fact <- factor(rep(1:4, length = 18))
> tapply(fact, fact, length) #same as table(fact)
1 2 3 4
5 5 4 4
如果上面这段不足以解释tapply的作用,我们可以看看下面这段
> tapply(1:18, fact, sum)
1 2 3 4
45 50 36 40
上面这段code的作用就是将fact展开(fact只包含1到4四个level),然后将1:18分别循环对应到1到4下面,然后将每列相加。换一种说法,就像是把1:18顺序放到列名为1,2,3,4的表格中,然后求colSums:
Col.Names 1 2 3 4
Row1 1 2 3 4
Row2 5 6 7 8
Row3 9 10 11 12
Row4 13 14 15 16
Row5 17 18
colSums 45 50 36 40
当INDEX时一个多元的list的时候,情况会复杂一点。
> ind <- list(c(1, 2, 2, 2), c("A", "A", "B", "B"))
> table(ind)
ind.2
ind.1 A B
1 1 0
2 1 2
上面那个对ind使用的table(),作用是将list中的两个对应起来,这样,A和1对应只有一次,A和2对应一次,B和2对应2次,而1和B没有对应,所以就有了上表(即维度为ind.1和ind.2的那个结果)。如果我这时调用tapply会有什么作用呢?
> tapply(1:4, ind) #FUN is not specified
[1] 1 2 4 4
> tapply(1:4, ind, sum) #FUN is specified
A B
1 1 NA
2 2 7
第一段的处理是:在FUN缺失时的情况下,tapply默认返回一系列下标,当FUN明确的时候,X的数值就按照这一系列下标所表示的对应位置做计算。需要注意的是,ind此时是一个2元的list,我们可以将table(ind)的结果看作一个matrix: M, 那么M[1] 就是A1,M[2]就是A2,M[3]就是B1,M[4]就是B2。
此例中由于M[3]位置为空,而M[4]的位置上有两个数据,所以tapply(1:4, ind)的后两个元素返回的下标都是4。当明确了FUN为sum的时候,1:4的后两个元素在M[4]的位置上相加,就得到7。
回想前一篇讲aggregate这个函数,其实也可以实现类似效果,对比一下tapply(1:4, ind, sum)也许更容易理解。
> aggregate(1:4, ind, sum)
Group.1 Group.2 x
1 1 A 1
2 2 A 2
3 2 B 7
---------------------------------------------------------------------------------
3. by(data, INDICES, FUN, ..., simplify = T)
将tapply发扬光大到matrix和data frame
参数不再赘述,与tapply大同小异。
> by(mtcars[,c(1,3,4)], mtcars$cyl, sum)
mtcars$cyl: 4
[1] 2358.8
------------------------------------------------------------
mtcars$cyl: 6
[1] 2277.4
------------------------------------------------------------
mtcars$cyl: 8
[1] 8083.8
> by(mtcars[,1], mtcars[,c(2,9)], sum)
cyl: 4
am: 0
[1] 68.7
------------------------------------------------------------
cyl: 6
am: 0
[1] 76.5
------------------------------------------------------------
cyl: 8
am: 0
[1] 180.6
------------------------------------------------------------
cyl: 4
am: 1
[1] 224.6
------------------------------------------------------------
cyl: 6
am: 1
[1] 61.7
------------------------------------------------------------
cyl: 8
am: 1
[1] 30.8
看到这样的结果,是不是让人忍俊不禁又想起了aggregate函数。。。
> aggregate(mtcars[,1], mtcars[,c(2,9)], sum)
cyl am x
1 4 0 68.7
2 6 0 76.5
3 8 0 180.6
4 4 1 224.6
5 6 1 61.7
6 8 1 30.8
---------------------------------------------------------------------------------
4. eapply(env, FUN, ..., all.names = F, USE.NAMES = T)
对一个环境中的变量进行计算
> .GlobalEnv$b <- 2:11 #Clear all variables in the global env. before using this clause
> .GlobalEnv$a <- 1:10
> eapply(.GlobalEnv, mean)
$a
[1] 5.5
$b
[1] 6.5
> unlist(eapply(.GlobalEnv, mean, USE.NAMES = FALSE))
[1] 5.5 6.5
不多讲这个了,目前我还没用过这个函数,不敢断言用途是否广泛。
-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-
说到这里,我们可以暂停一下,lapply,rapply和mapply留待下回分解。
ref: 请自行搜索以上四个函数的R Documents
0 0
- R: 矩阵运算及常用函数 III - *apply Part I
- R: 矩阵运算及常用函数 IV - *apply Part II
- R: 矩阵运算及常用函数 V - plyr Part I
- R: 矩阵运算及常用函数 I - split
- R: 矩阵运算及常用函数 II - aggregate
- R:矩阵apply()函数
- r语言常用函数apply及subset函数
- R语言入门基础教程:常用运算函数
- R语言矩阵运算
- R语言矩阵运算
- R语言矩阵运算
- R语言矩阵运算
- R语言矩阵运算
- R:一般矩阵运算
- R的矩阵运算
- R语言矩阵运算
- R语言 矩阵运算
- R语言矩阵运算
- zuiqingchun
- Linux常用命令(三十一) - grep
- BZOJ 3626 LNOI 2014 LCA 树链剖分
- springmvc在ajax请求出现406
- 3. Dubbo原理解析-Dubbo内核实现之动态编译
- R: 矩阵运算及常用函数 III - *apply Part I
- 一句话获取机器ip
- POJ 1654 Area 有向面积
- Candy
- python subprocess
- Android四大组件详解
- linux 下查看一个进程运行路径的方法
- J.U.C原子工具类AtomicXXX中,set和lazySet的区别
- 人见人爱A^B