(四)控制流、函数与apply家族

控制流

R语言的循环和控制流包括:if、else、 next、while、for等语句。
R语句的缩进多用大括号,如for循环后面的操作需放在大括号里面;一般来说if条件后面的操作可以不用大括号括起来, 但是当使用if-else结构时必须使用大括号将操作括起来。next的作用类似于Python中的continue,表示跳过。while表示重复操作,循环内部一般需要一个break来跳出循环。此外,whileforif后面的条件语句都需要用小括号括起来。
R中函数直接使用<-进行赋值给一个变量,函数使用return()返回值,若不使用return语句,默认把最后的语句作为返回值。

func <- function(){
n<-1  
while (TRUE){
    if (n%%2==0){
      print('even number: ',n)
    }else{print('odd number: ',n)}
    if(n>10)
      print('too large, exit....')
      break
    n<-n+1
  }
}

apply家族

apply家族函数是进行向量化运算的运算方法,而且由于其基于C语言编写的,与for循环相比,能大大地提高运算速度。apply家族函数众多,包括applysapplylapplyvapplymapplytapplyrapplyeapply,各个函数的用途如下图所示。这里主要讲一下应用较多的applysapply函数。

1、apply

apply函数可以对矩阵、数据框、数组(二维、多维),按行或列进行循环计算,对子元素进行迭代,并把子元素以参数传递的形式给自定义的FUN函数中,并返回计算结果。使用方法如下:

apply(X, MARGIN, FUN, ...)
X 表示数组、矩阵或数据框
MARGIN 表示函数作用于行还是列,1表示行,2表示列
FUN 作用于行或列的函数
... 表示函数的参数

> options(digits=2);student <- c('andy','lucy','mike','jacky');score <- c(88,92,67,75);df<-data.frame(student,score,stringsAsFactors=FALSE);df
  student score
1    andy    88
2    lucy    92
3    mike    67
4   jacky    75
> df$salary<-c(200,320,90,NA);df
  student score salary
1    andy    88    200
2    lucy    92    320
3    mike    67     90
4   jacky    75     NA
> average <- apply(df[,c(2:3)],2,mean,na.rm=TRUE);df<-rbind(df,c("average",average));df
  student score           salary
1    andy    88              200
2    lucy    92              320
3    mike    67               90
4   jacky    75             <NA>
5 average  80.5 203.333333333333
####这里需要注意的是由于行合并的时候用了c("average",average),因此average数字也被换成了字符串,为了方便后续计算,最好还是将他们转换为numeric
> df[,c(2,3)]<-apply(df[,c(2,3)], 2, as.numeric);df
  student score salary
1    andy    88    200
2    lucy    92    320
3    mike    67     90
4   jacky    75     NA
5 average    80    203

再来看一个稍微复杂点的例子,这回我们使用自定义的函数,完成对矩阵的第一列加一,第二列等于行平均值:

###首先定义函数
func <- function(x, c1, c2){
  c(sum(x[c1], 1), x[c2]<-mean(x[c2]))
}

###使用自定义函数
> x <- cbind(x1 = 3, x2 = c(4:1, 2:5)); x
     x1 x2
[1,]  3  4
[2,]  3  3
[3,]  3  2
[4,]  3  1
[5,]  3  2
[6,]  3  3
[7,]  3  4
[8,]  3  5
> apply(x,1,func,c1='x1',c2=c('x1','x2'))
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]  4.0    4  4.0    4  4.0    4  4.0    4
[2,]  3.5    3  2.5    2  2.5    3  3.5    4
###另一种更简单的方法
> x<-data.frame(x1=x[,1]+1,x2=rowMeans(x));x
  x1  x2
1  4 3.5
2  4 3.0
3  4 2.5
4  4 2.0
5  4 2.5
6  4 3.0
7  4 3.5
8  4 4.0

2、lapply

lapply函数是一个最基础循环操作函数之一,用来对list、data.frame数据集进行循环,并返回和X长度同样的list结构作为结果集。使用方法如下:

lapply(X, FUNC, ...)
X list,data.frame数据结构(使用data.frame时,作用于列)
FUN 作用函数
... 参数

> x <- list(a = 1:10, b = rnorm(6,10,5), c = c(TRUE,FALSE,FALSE,TRUE));x
$a
 [1]  1  2  3  4  5  6  7  8  9 10

$b
[1]  8.2 11.0 11.0 11.9 11.4  6.0

$c
[1]  TRUE FALSE FALSE  TRUE

> lapply(x, fivenum)
$a
[1]  1.0  3.0  5.5  8.0 10.0

$b
[1]  6.0  8.2 11.0 11.4 11.9

$c
[1] 0.0 0.0 0.5 1.0 1.0
#######################对矩阵使用会出现错误
> x <- cbind(x1=3, x2=c(2:1,4:5));x
     x1 x2
[1,]  3  2
[2,]  3  1
[3,]  3  4
[4,]  3  5
> class(x); lapply(x,sum)
[1] "matrix"
[[1]]
[1] 3

[[2]]
[1] 3

[[3]]
[1] 3

[[4]]
[1] 3

[[5]]
[1] 2

[[6]]
[1] 1

[[7]]
[1] 4

[[8]]
[1] 5

> x<-as.data.frame(x);lapply(x,sum)
$x1
[1] 12

$x2
[1] 12

3、sapply

sapply函数是一个简化版的lapply,sapply增加了2个参数simplify和USE.NAMES,主要就是让输出看起来更友好,返回值为向量,而不是list对象。

sapply(X, FUN, ..., simplify=TRUE, USE.NAMES = TRUE)
X 数组、矩阵、数据框
FUN 调用函数
... 函数参数
simplify 是否数组化,当值array时,输出结果按数组进行分组
USE.NAMES 如果X为字符串,TRUE设置字符串为数据名,FALSE不设置

> x <- cbind(x1=3, x2=c(2:1,4:5));x
     x1 x2
[1,]  3  2
[2,]  3  1
[3,]  3  4
[4,]  3  5
###对矩阵进行计算结果与lapply相同,无法得到想要的结果
> sapply(x, sum);
[1] 3 3 3 3 2 1 4 5
> sapply(data.frame(x), sum);
x1 x2 
12 12
###当simplify=FALSE和USE.NAMES=FALSE时候,那么sapply函数就等于lapply函数了
> sapply(data.frame(x), sum, simplify=FALSE, USE.NAMES=FALSE)
$x1
[1] 12

$x2
[1] 12

4、vapply

vapply类似于sapply,提供了FUN.VALUE参数,用来控制返回值的行名,这样可以让程序更健壮。

vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
X 数组、矩阵、数据框
FUN 自定义的调用函数
FUN.VALUE 定义返回值的行名row.names
… 函数参数
USE.NAMES 如果X为字符串,TRUE设置字符串为数据名,FALSE不设置

#对数据框的数据进行累计求和,并对每一行设置行名row.names
> x <- data.frame(cbind(x1=3, x2=c(2:1,4:5)));x
  x1 x2
1  3  2
2  3  1
3  3  4
4  3  5
> vapply(x,cumsum,FUN.VALUE=c('a'=0,'b'=0,'c'=0,'d'=0))
  x1 x2
a  3  2
b  6  3
c  9  7
d 12 12

转自:
掌握R语言中的apply函数族

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容