第三章第一节 apply族函数

3.1.1 apply()函数

    apply()对层、行、列、行和列应用函数,根据观测、变量和数据集不同层次的特征决定。语法格式为:

apply(dataset, MARGIN, FUN)

dataset是apply应用的数据集,数据结构是数组、矩阵或数据框。参数MARGIN是apply()应用的维度,MARGIN=1表示矩阵和数组的行,MARGIN=2表示矩阵和数组的列。参数FUN为应用的计算函数f(),必须大写,可带有f()的参数。FUN函数结果的长度确定apply()的返回值类型,通常为array类型,若返回值的向量长度不等,则返回list对象。

1.apply()的基本应用方法

eg1.指定维数行或列进行计算

> dar1=array(rep(1:3,3),dim=c(3,3))  #按列生成二维数组

> dar1

     [,1] [,2] [,3]

[1,]    1    1    1

[2,]    2    2    2

[3,]    3    3    3

> apply(dar1,MARGIN=1,FUN=sd)  #对行计算方差

[1] 0 0 0

> apply(dar1,2,mean)  #对列计算均值

[1] 2 2 2

eg2.高维计算margin=c(1,2)或3

    margin=c(1,2)是对不同层相同行列下标元素的多维计算,margin=3是对层进行的高维计算。

>dar2=array(rep(1:3,each=9),dim=c(3,3,3))   #按列生成三维数组dar2

>dar2

##        , , 1                     #层

##       [,1] [,2] [,3] 

##  [1,]    1    1    1 

##  [2,]    1    1    1 

##  [3,]    1    1    1     

##        , , 2                    #层

##       [,1] [,2] [,3] 

##  [1,]    2    2    2 

##  [2,]    2    2    2 

##  [3,]    2    2    2     

##        , , 3                   #层

##       [,1] [,2] [,3] 

##  [1,]    3    3    3 

##  [2,]    3    3    3 

##  [3,]    3    3    3 

> apply(dar2,3,sum)     #margin=3对层应用sum()

 [1]  9 18 27 

> apply(dar2,1:2,sum)  #对不同层行列下标相同的元素计算和  

                    #例如,c(1,1,1)+c(1,1,2)+c(1,1,3)

     [,1] [,2] [,3] 

[1,]    6    6    6 

[2,]    6    6    6 

[3,]    6    6    6 

    若MARGIN>=data的维数,函数f()计算结果将是某一值,甚至产生无效值。

> apply(dar1,1:2,FUN=sd)    #二维数组dar1不能进行不同层对应元素的计算

                  [,1]  [,2]  [,3] 

         [1,]   NA   NA   NA 

         [2,]   NA   NA   NA 

         [3,]   NA   NA   NA 

以上sd()、sum()或mean()对变量应用的返回值长度n=1,与dim(data)[MARGIN]相同。若f()函数返回值长度n>1,则apply函数结果的维度为c(n, dim(data)[MARGIN])。

2.apply()的分组数据应用

函数apply()的应用有计算分组数据的分位数。分位数将数据根据数值范围分成等分量,可知向量整体数值和元素的数值排列。例如,

> dv1=c(1:5)

> dvquan1=quantile(dv1)

> dvquan1

  0%  25%  50%  75% 100%

   1    2    3    4    5

> dv1.1=c(1:3)

> dvquan1.1=quantile(dv1.1)   #数值范围四等分

> dvquan1.1

  0%  25%  50%  75% 100%

 1.0  1.5  2.0  2.5  3.0

参数prev设置向量等分的范围,例如prev可等于seq(1:0,0.2),即使prev=c(1.0,0.75,0.5,0.2)仍表示四等分。

> dvquan1.2=quantile(dv1,prev=c(1,0.75,0.5,0.25)) #prev的缺省设置

> dvquan1.2

  0%  25%  50%  75% 100%

   1    2    3    4    5

> dvquan2=quantile(dv1,prev=c(0.75,0.5,0.2))  #prev是等分的参数

> dvquan2

  0%  25%  50%  75% 100%

   1    2    3    4    5

> dvquan3=quantile(rep(1,5))   #quantile()是对输入数据的等分

> dvquan3

  0%  25%  50%  75% 100%

   1    1    1    1    1

eg3.计算数据集thuesen的分位数

>library(ISwR)

>data(thuesen)

> daf=apply(thuesen,2,quantile,na.rm=T)  #对thuesen的每一列应用quantile

> daf

        Blood.glucose   short.velocity

0%           4.200          1.030

25%          7.075          1.185

50%          9.400          1.270

75%         12.700          1.420

100%        19.500          1.950

编程应用1:计算三维数组的分位数

学生成绩数据集的三维数组dar2,计算学生成绩观测的数学期望,可知道学生的综合得分,并且据此进行A~E等级的打分。

> dmean=apply(dar2,c(1,2),mean)

> dmean

       [,1]    [,2]    [,3]    [,4]    [,5]    [,6]   [,7]

[1,] 70.0825 70.5425 67.5275 73.3525 71.2150 71.2375 63.665

[2,] 70.1925 67.2175 68.0775 60.2225 72.2875 69.4275 66.600

为输出每个学生的综合成绩,必须将学号增加到成绩栏,因此构建数据框stuscores,将矩阵dmean转到数据框的变量,注意应保持原来的顺序。

>dv=as.vector(dmean)

>stuscores=data.frame("学号"=dafstu[,1],"综合成绩"=dv)

>stuscores

学生的成绩比较接近,所以用原有的五分制,不能表示学生在班级的学习水平间距离。因此用综合成绩的四分位数表示A~E五个等级,否则可用函数funfactor()完成。

>fator1=quantile(dv,prev=c(.8,.6,.4,.2))

factor1[2:5]=factor1

factor1[1]=100.0

names(factor1)=c("100%","80%","60%","40%","20%")

gradeterm=c("A","B","C","D","E")

for(i in 1:4)

 {

  gradelog=dv>=factor1[i+1]&dv<factor1[i]

  dv[gradelog]=gradeterm[i]

 }

dv[dv<factor1[5]]=gradeterm[5]

dv

 [1] "C" "B" "B" "D" "D" "D" "A" "E" "B" "A" "A" "C" "E" "E"

length(dv)

> stuscores=cbind(stuscores,grade=dv)

> stuscores

      学号  综合成绩  grade

1  3600101  70.0825     C

2  3600102  70.1925     B

3  3600103  70.5425     B

4  3600104  67.2175     D

5  3600105  67.5275     D

6  3600106  68.0775     D

7  3600107  73.3525     A

8  3600108  60.2225     E

9  3600109  71.2150     B

10 3600110  72.2875     A

11 3600111  71.2375     A

12 3600112  69.4275     C

13 3600113  63.6650     E

14 3600114  66.6000     E

3.1.2 lapply(),sapply()和vapply()函数

lapply()和sapply()只能应用在二维数据结构,例如列表的元素,数据框的变量,而且并不需要指定维度。lappy()是最基本的原型函数,不妨知道它是R语言最简单的泛函,仅此而已。lapply(),sapply()和vapply()的两个主要参数是data和f()。data的数据类型是列表或向量,函数对所有列表元素、数据框变量应用f()函数。 lapply()返回的结果是列表,长度与data相同,sapply()返回的结果是向量,矩阵或数组,结果需要做预测。而vapply()函数将对返回结果的值进行类型检查,参数FUN.VALUE设置返回值类型,因此vapply()是结果可预测的sapply()版。所以不可在函数内部用sapply(),而应使用vapply()。lapply()和sapply()可实现数据结构操作的大多数功能,包括创建数据结构、取子集等,然而这并不是它们的优势。访问操作与"["相同,"["可提取数据结构的分量。

1.lapply()的基本应用

eg4.  函数lapply()应用在列表

> stuscores=list(digital.circuit=c(80,88,94,70,86,79,98),analogous.circuit=c(99,87,100,77,83,80,92),electrocircuit=c(82,90,96,80,80,71,95))

      #建立列表,以行为单位处理分组数据        

>dlist= lapply(stuscores,quantile,probs=c(0.5,0.7,0.9)) #计算0.5,0.7,0.9的分位数

>dlist

$digitalcircuit

 50%  70%  90%

 86.0  89.2  95.6

$analogouscircuit

 50%  70%  90%

 87.0  93.4  99.4

$electrocircuit

 50%  70%  90%

 82.0  91.0  95.4

2.sapply()的基本应用

    sapply是对结果进行simplify的lappy(),并且应用在数据框。

eg5.1 sapply()建立数据结构

>dv1=c(1:4)

> dafr1=sapply(dv1,FUN=rep,times=4)  #按列建立矩阵

> dafr1

     [,1] [,2] [,3] [,4]

[1,]    1    2    3    4

[2,]    1    2    3    4

[3,]    1    2    3    4

[4,]    1    2    3    4

eg5.2 sapply()取子集

> sapply(dar1,function(data) data[4])  #sapply()只能用在数据框

 [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

[25] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

[49] NA NA NA NA NA NA NA NA

 > dv2= sapply(dafrstu[2:5],function(data) data[4])  #取每一列的第四个元素

专业课平均成绩         社会实践大学英语平均成绩         英语四级

           79.93            78.83            61.46            48.65

注意不是取数据框data的第四个变量,而是所有列的第四个元素。

> class(dv2)  #dv2是向量

[1] "numeric"

> typeof(dv2)

[1] "double"

> mode(dv2)

[1] "numeric"

> str(dv2)    #dv2是向量

 Named num [1:4] 79.9 78.8 61.5 48.6

 - attr(*, "names")= chr [1:4] "专业课平均成绩" "社会实践" "大学英语平均成绩" "英语四级"

eg6. 应用在thuesen数据集

> dim(thuesen)

[1] 24  2

> dvquan1=sapply(thuesen,quantile,na.rm=T)  #sapply()应用在数据框的变量

> dvquan1

        Blood.glucose     short.velocity

0%           4.200          1.030

25%          7.075          1.185

50%          9.400          1.270

75%         12.700          1.420

100%        19.500          1.950

    从分位数可知,blood.glucose在4.2和19.5间,50%在9.4以上。short.velocity

在1.03和1.95间,50%在1.27以上。

3.vapply()

    函数vapply()的返回值的类型用参数FUN.VALUE预先定义,而参数USE.NAMES 判定data是否有标签,若为无标签(T),则应命名。

eg7.1设置函数vapply()结果类型

    用retval变量设置返回值长度和类型,如果FUN函数获得的结果和retval的设置不一致,则返回出错信息。

> probs=c(1:3/4)   #四分位数的三个分位数,三个数

> probs
[1] 0.25 0.50 0.75

> retval=c(0,0,0)  #设置返回值是向量,有三个元素

> vapply(scores,quantile,FUN.VALUE=retval,probs=probs) 

            digitalcircuit   analogouscircuit    electrocircuit

25%           79.5             81.5           80.0

50%           86.0             87.0           82.0

75%           91.0             95.5           92.5

 >probs=c(1:4/4)    #四分位数,四个数与返回值类型不符

> vapply(scores,quantile,FUN.VALUE=retval,probs=probs)

Error in vapply(scores, quantile, FUN.VALUE = retval, probs = probs) :

  值的长度必需为3,

 但FUN(X[[1]])结果的长度却是4

   因为vapply()检验返回值类型,发现函数的计算结果与返回值类型不符,所以错误。

4.mapply()的应用

    函数mapply()用在函数的参数有多个不同值的时候,参数顺序和sapply()不同。标准格式:

mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)

data数据类型为向量或列表,函数FUN对元素应用;若参数长度为1,得到的结果和sapply相同;但如果参数长度不等于1,FUN函数将按向量顺序和循环规则(短向量重复)逐个取参数应用到对应数据元素。

eg8.函数mapply() 建立数据结构

> dafr2=sapply(dv1,FUN=rep,times=1:4)  #sapply()不能用在函数参数有不同值

Error in FUN(X[[i]], ...) : 'times'参数不对

> dafr2=mapply(dv1,FUN=rep,times=1:4)

> dafr2

[[1]]

[1] 1

[[2]]

[1] 2 2

[[3]]

[1] 3 3 3

[[4]]

[1] 4 4 4 4

3.1.3 tapply()和同类系列函数

tapply()根据一个因子向量对数据向量进行分类,得到的分组数据是不等长分组,然后对每个分组应用函数fun()。tapply()语法格式:

tapply(data, index, FUN = NULL, ..., simplify = TRUE)

data只能是向量,index为因子向量,长度应与data相同。返回值是向量,若simplify=FALSE输出列表。index向量因子有两个形式:1)数据框的变量2)指定的分类向量。可用c()生成不规则的因子,也可用gl()生成等长分类的向量。

同类系列函数有split()和by()。split()函数仅对数据框或一个变量根据另一个变量分组,输出是列表。by()能对数据框和矩阵根据因子分组,可应用多变量函数fun()。

 eg9.函数gl()生成分类向量

> data1=c(1:12)

[1]  1  2  3  4  5  6  7  8  9 10 11 12

> factor2=gl(2,6,labels=c("Good","Bad"))   #生成两个分类各6个元素的向量

> factor2

factor2

 [1] Good Good Good Good Good Good Bad  Bad  Bad  Bad  Bad  Bad

Levels: Good Bad

>tapply(data1,factor2,length) 

Good  Bad

   6    6 

> tapply(data1, factor2, sum)

Good  Bad  

  21   57

这说明坏与西斯一样总比好的绝地有力量速度快,所以伟大导师马克思说人不是靠身体的力量和敏捷、当时的社会地位、别人的毁誉成功,而是靠意志、性格(能力)和知识的力量。

eg10.tapply()的实际应用

  mtcars 是不同类型汽车道路测试的数据框类型数据

>str(mtcars) 

'data.frame':   32 obs. of  11 variables: 

 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ... 

 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ... 

 $ disp: num  160 160 108 258 360 ... 

 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ... 

 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ... 

 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ... 

 $ qsec: num  16.5 17 18.6 19.4 17 ... 

 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ... 

 $ am  : num  1 1 1 0 0 0 0 0 0 0 ... 

 $ gear: num  4 4 4 3 3 3 3 4 4 4 ... 

 $ carb: num  4 4 1 1 2 1 4 2 2 4 ... 

 

    数据集每加仑汽油行驶里程mpg,气缸规格cyl,马力hp。

(1)计算四缸汽车平均mpg

> tapply(mpg,cyl,mean)

4 6 8

26.66 19.74 15.10

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值