变量用于临时存储数据,而函数用于操作数据,实现代码的重复使用。在R中,函数只是另一种数据类型的变量,可以被分配,操作,甚至把函数作为参数传递给其他函数。分支控制和循环控制,和通用编程语言的风格很相似,但是,不要因为R具有这些元素,就把R作为通用编程语言来看待,R的最小变量是向量,是一种面向数组(Array-Oriented)的语言。在编程时,尽量用array的方式思考,避免使用循环(for,while,repeat)控制,而使用apply函数家族实现计算的迭代,这是R语言的特色,把特定的函数应用于向量,列表或数组中的每个元素上。

一,R函数的风格

R通过function关键字定义函数,函数主要由函数名称,参数,运行的代码块和返回值组成,函数名称是变量,参数是调用函数时需要传递的形式参数;代码块是由由大括号构成,是调用函数时需要执行的代码逻辑;R的函数不需要显式地使用return关键字明确返回值,R函数的计算的最后一个值将自动作为返回值。

1,创建函数

例如,创建一个函数,并把函数赋值给avg变量,可以认为函数的名称是avg,其有两个参数a和b,大括号内的代码是函数体,实现的功能是求两个数的平均值。在R中创建函数时,如果函数体只有一行代码,可以省略大括号。

avg <- function(a,b)
{
mead(c(a,b))
}

该函数没有显式调用return关键字,函数代码块种计算的最后一次自动最为返回值,在avg函数种,代码块调用系统函数mean,返回参数a和b的平均值,调用格式是函数名称(形式参数):

> avg(,)
[] 2.5

调用函数时,如果不命名参数,则R按照位置匹配参数,因此,2对应形式参数a,3对应形式参数b。如果要改变传递参数的顺序,则可以传入命名参数:

> avg(b=,a=)
[] 2.5

可以为函数的参数设置默认值,当调用函数时,如果没有为参数传递相应的值,那么函数将自动使用默认值作为函数代码块执行的当前值。

> avg <- function(a=,b=)mean(c(a,b))
> avg()
[]

虽然函数中最后一行代码的值是自动返回的,但是,为了便于阅读代码,建议使用return函数,清晰地指定要返回的值,return函数除了指定函数的返回值之外,还能使函数退出,不再继续执行后面的代码。

> avg <- function(a=,b=) return(mean(c(a,b)))

2,把函数作为参数传递给其他函数

函数本质上是一个函数类型的变量,和其他类型的变量一样,能够作为函数的形式参数,传递给其他函数,例如:

> fn_call <- function(x,a,b)x(a,b)
> fn_call(avg,,)
[] 1.5

R提供一个系统函数do.call(fun,args),用于调用其他函数,第一个参数是函数变量,第二个参数是有参数构成的列表:

> do.call(avg,args=list(,))
[] 1.5

3,查看函数的定义

通过函数args用于显示函数的头部文本,用于显示函数的头部定义,例如:

> args(avg)
function (a = , b = )
NULL

body(fun)函数用于返回函数的代码块,例如:

> body(avg)
mean(c(a, b))

除了这两个函数,还有函数formals(fun),用于查看函数的参数及其默认值,如果函数没有定义参数的默认值,那么只显示参数名,formals显示的参数名格式是$参数名。函数deparse(fun)用于查看函数调用的函数。

4,特殊的参数

R提供了一个特殊的运算符(...),该运算符允许函数具有任意多个的参数,并且不需要在函数定义中指定。

avg <- function(a,b, ...) mead(c(a,b))

二,分支控制

分支和循环是通用编程语言中必不可少的两大流程控制元素,分支控制是根据条件表达式的结果,执行不同的代码段。

1,if-else控制

经典的流程控制关键字是if-else,并可以把多个if-else语句连接到一起:

if ( test_expression1) {
statement1
} else if ( test_expression2) {
statement2
} else {
statement3
}

2,ifelse控制

ifelse控制是,在一个函数中,结合了if-else的功能,其语法是:

ifelse(test, yes, no)

当test条件为TRUE时,返回yes表达式的值,当test条件为FALSE时,返回no表达式的值。

> ifelse(c(,,)>=,'Greater','Less')
[] "Less" "Greater" "Greater"

对于ifelse的返回值,官方文档的描述是:

A vector of the same length and attributes (including dimensions and "class") as test and data values from the values of yes or no. The mode of the answer will be coerced from logical to accommodate first any values taken from yes and then any values taken from no.

注意:返回值的class属性跟test表达式相同,其mode属性是由 yes 或 no表达式确定的。

当ifelse()用于返回Date类型的对象时,返回值是numeric类型,而不是Date类型,这是因为返回值的class是由test表达式决定的。

dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - , dates)

解决方案是:把返回值的class重新设置为Date类型。

dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - , dates)
class(dates) <- 'Date'

3,switch函数

如果分支较多,可以使用switch函数实现分支的选择,switch函数的第一个参数是表达式(exp),通常是一个字符串;当表达式(exp)匹配后续的参数名(即变量名)时,返回参数的值:

> color <- function(t) switch(t,r='red',g='green',b='blue')
> color('r')
[] "red"

如果不匹配任何参数名,switch函数不返回任何值,可以添加一个匿名的参数,当表达式(exp)匹配不上任意一个命名参数时,switch函数将返回匿名参数的值:

> color <- function(t) switch(t,r='red',g='green',b='blue', 'error')
> color('d')
[] "error"

三,循环控制

循环控制是根据条件重复执行代码块,为了避免无限循环,可以根据条件结束循环。循环控制语句是repeat、while和for,R的向量化自带循环特性,减少了循环语句使用的场景,但是在重复执行代码时,循环控制还是非常有用。

1,repeat 循环

repeat 循环:先执行代码,遇到break关键字,结束循环,也可以在break关键字前增减if(test)语句,当指定的条件成立(为TRUE)时,执行break关键字,结束循环:

repeat {
code
if(test) break
}

2,while 循环

while 循环:先检测条件,如果条件为TRUE,执行code;如果条件为FALSE,结束循环:

while(test)
{
code
}

3,for 循环

for 循环:使用迭代器和一个向量参数,在每个循环中,迭代器变量从向量中取得一个值,直到迭代所有得向量:

for(i in c(:))
{
code
}

4,向量化的循环

R是向量化的编程语言,这使得R自身带有循环的特性,而不用使用循环控制语句。关于向量化的循环控制,请阅读我的博客文章

R语言学习 第九篇:plyr包

R语言学习 第十篇:操作符

 

参考文档:

How to prevent ifelse() from turning Date objects into numeric objects

R语言学习 第四篇:函数和流程控制的更多相关文章

  1. R语言学习 第八篇:常用的数据处理函数

    Basic包是R语言预装的开发包,包含了常用的数据处理函数,可以对数据进行简单地清理和转换,也可以在使用其他转换函数之前,对数据进行预处理,必须熟练掌握常用的数据处理函数,本文分享在数据处理时,经常使 ...

  2. R语言学习 第十篇:操作符

    运算符是R语言中最基础的存在,熟悉运算符的使用,是熟练使用R处理数据的基础,操作符,顾名思义,是对数据进行运算的符号,R有自己的一套操作符,实现变量的赋值,引用,运算等功能. 一,赋值符号 为变量赋值 ...

  3. R语言学习 第十一篇:日期和时间

    R语言的基础包中提供了三种基本类型用于处理日期和时间,Date用于处理日期,它不包括时间和时区信息:POSIXct/POSIXlt用于处理日期和时间,其中包括了日期.时间和时区信息.R内部在存储日期和 ...

  4. R语言学习 第五篇:字符串操作

    文本数据存储在字符向量中,字符向量的每个元素都是字符串,而非单独的字符.在R中,可以使用双引号,或单引号表示字符. 一,字符串中的字符数量 函数nchar()用于获得字符串中的字符数量: > s ...

  5. R语言学习 第十篇:包

    包(Package)是实现特定功能的.预先写好的代码库(library),通俗地说,包是含有函数.数据等的功能模块.R拥有大量的软件包,许多包都是由某一领域的专家编写的,但并不是所有的包都有很高的质量 ...

  6. R语言学习 第三篇:数据框

    数据框(data.frame)是最常用的数据结构,用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同数据列的数据类型可以相同,也可以不同,但是每列的行数(长度)必须相同.数据框的每列 ...

  7. R语言学习 第七篇:列表

    列表(List)是R中最复杂的数据类型,一般来说,列表是数据对象的有序集合,但是,列表的各个元素(item)的数据类型可以不同,每个元素的长度可以不同,是R中最灵活的数据类型.列表项可以是列表类型,因 ...

  8. R语言学习笔记:查看函数的R源代码

    getAnywhere 该函数可以返回一些函数的R源代码,如: getAnywhere(kmeans) 该函数具体用法,请参看官方说明. Retrieve an R Object, Including ...

  9. R语言学习笔记

    向量化的函数 向量化的函数 ifelse/which/where/any/all/cumsum/cumprod/对于矩阵而言,可以使用rowSums/colSums.对于“穷举所有组合问题" ...

随机推荐

  1. LeetCode题解之N-ary Tree Preorder Traversal

    1.题目描述 2.问题分析 采用递归方法是标准解法. 3.代码 vector<int> preorder(Node* root) { vector<int> v; preNor ...

  2. Ionic 命令

    在WebStorm的设置中设置下面的命令后, 可以通过 工具 -->External Tools 中选中来执行指定脚本 C:\Windows\System32\WindowsPowerShell ...

  3. 关于SQLSERVER走起公众帐号推送视频的通知

    关于SQLSERVER走起公众帐号推送视频的通知 为了SQLSERVER走起这个微博帐号和微信帐号更加多样化,内容更加丰富 也为了发挥微信.微博的媒介传播威力,在以后的微博.微信每日推送中会在适当的时 ...

  4. docker in all

    docker vs hyper-v,vmware,xen,kvm docker host, docker container, docker engineen, docker image images ...

  5. Sql server中的 nvarchar(max) 到底有多大?(转载)

    问题: SQL server中的nvarchar(max)最大的长度是4000个字吗? 如果字段的内容超过4000个字时用什么类型呢?text 还是binary?他们的最大长度是多少?比如字段放的是长 ...

  6. QT的初步学习笔记

    一.Qt简介 1.Qt是什么:图形用户界面程序框架  能做界面的还有什么:MFC.GTK+ 2.Qt的由来和发展 3.为什么选择Qt 二.Qt环境与工具 1.工具   a.Qt助手:里面详细说明了Qt ...

  7. 【MYSQL】语法复习

    一.数据类型 截图来源: http://www.runoob.com/mysql/mysql-data-types.html 二.基本语句 1.创建数据表 -- 主键自增,T_User CREATE ...

  8. 用apiDoc简化接口开发

    身为程序员最讨厌看到的代码没有注释,自己的代码却讨厌写注释,觉得麻烦,接口也是这样. 比如公司要做一个H5活动的页面,开发文档已经发到后端开发.设计.与前端的邮箱了,其实这个时候就可以开始开发了.开发 ...

  9. [技术] OIer的C++标准库 : STL入门

    注: 本文主要摘取STL在OI中的常用技巧应用, 所以可能会重点说明容器部分和算法部分, 且不会讨论所有支持的函数/操作并主要讨论 C++11 前支持的特性. 如果需要详细完整的介绍请自行查阅标准文档 ...

  10. Redis系列六:redis相关功能

    一. 慢查询原因分析 与mysql一样:当执行时间超过阀值,会将发生时间耗时的命令记录 redis命令生命周期:发送 排队 执行 返回慢查询只统计第3个执行步骤的时间 预设阀值:两种方式,默认为10毫 ...