首页 > > > 【R语言】条件语句与自定义函数
编程中要实现分支结构,就需要用到条件语句。
R语言中的条件语句的一般格式为:
(1) 一个分支
if(条件) {
执行体
}(2) 两个分支
if(条件) {
执行体1
} else {
执行体2
}例如,实现计算 的绝对值功能:
if(x < ) {
y = -x
} else {
y = x
}(3) 更多分支
if(条件1) {
执行体1
} else if(条件2) {
执行体2
} else {
执行体n
}注:中间可以有任意多个 else if 块。多个分支的意思是,若满足“条件1”,则执行“执行体1”;其它的若满足“条件2”,则执行“执行体2”;......其它的,执行“执行体n”。要特别注意:分支的本意就是,不同分支之间不存在交叉(重叠)。
例如,实现将百分制分数转化为五级制分数:
if(score >= 90) {
res = "优"
} else if(score >= 80) {
res = "良"
} else if(score >= 70) {
res = "中"
} else if(score >= 60) {
res = "及格"
} else {
res = "不及格"
}注意:若先写>=60,结果就不对了。
1. 什么是自定义函数
编程中的函数,是用来实现某个功能,其一般形式为:
(返回值1,..., 返回值m) = 函数名(输入1, ..., 输入n)
你只要把输入给它,它就能在内部进行相应处理,把你想要的返回值给你。
这些输入和返回值,在函数定义时,都要有固定的类型(模具)限制,叫做形参(形式上的参数);在函数调用时,必须给它对应类型的具体数值,才能真正的去做处理,这叫做实参(实际的参数)。
所以,定义函数就好比创造一个模具,调用函数就好比用模具批量生成产品。
使用函数最大的好处,就是将实现某个功能,封装成模具,从而可以反复使用。这就避免了写大量重复的代码,程序的可读性也大大加强。
以前面的“百分制分数转化为五级制分数”为例,如果来一个百分制分数,就这样转化一次,10个学生分数,就得写100多行代码。所以有必要封装成一个函数。
2. R中自定义函数的语法
R语言中,自定义函数的一般格式为:
函数名 = function(输入1, ..., 输入n) {
函数体
return(返回值)
}注:return并不是必须的,默认函数体最后一行的值作为返回值,也就是说“return(返回值)”完全可以换成“返回值”。
3. 怎么自定义一个函数
以“百分制分数转化为五级制分数”问题为例,我需要自定义一个函数,能够实现“把百分制分数转化为五级制分数”的功能。
基于前面函数的理解,
第一步,分析输入和输出,设计函数外形:
本问题,输入有1个:百分制分数,数值型;输出有1个:五进制分数,字符串
然后就可以设计自定义函数的外形:
Score_Conv = function(score) {
# 实现将一个百分制分数转化为五级分数
# 输入参数: score为数值型, 百分制分数
# 返回值: res为字符串型, 五级分数
...
}注:函数名和变量可以随便起名,但是建议用有含义的单词。另外,为函数增加注释是一个好习惯。这些都是为了代码的可读性。
第二步,梳理功能的实现过程
拿一个具体的输入,比如76分,分析怎么到达对应的五级分数”良“。这依赖于对五级分数界限的选取,选定之后做分支判断即可实现,即前文的条件语句中的例子那样。
注:复杂的功能,就需要更耐心的梳理和思考甚至借助一些算法,当然也离不开代码片段的调试。
score = 76
if(score >= 90) {
res = "优"
} else if(score >= 80) {
res = "良"
} else if(score >= 70) {
res = "中"
} else if(score >= 60) {
res = "及格"
} else {
res = "不及格"
}
res
把一个具体的输入,调试通过,得到正确的返回值结果,这一步骤很有必要。
第三步,将第二步的代码封装到函数体
Score_Conv <- function(score) {
if(score >= 90) {
res = "优"
} else if(score >= 80) {
res = "良"
} else if(score >= 70) {
res = "中"
} else if(score >= 60) {
res = "及格"
} else {
res = "不及格"
}
res
}基本就是原样作为函数体放入函数,原来的变量赋值语句不需要了,只需要形参。
4. 调用函数
要调用自定义函数,需要选中并执行函数代码(加载到当前变量窗口),或者将函数保存为同名的 Score_Conv.R 文件,再执行source('Score_Conv.R'),效果是一样的。
然后就可以调用函数了,给它一个实参76,输出结果为”中“:
Score_Conv(76)
5. 向量化改进
我们希望自定义函数,也能处理向量输入,即输入多个百分制分数,能一下都转化为五级分数。这也是所谓的”向量化编程“思维,就是要习惯用向量(矩阵)去思考、去表达。
有两种方法:
(1)修改自定义函数
将输入参数设计为数值向量,函数体也要相应的修改,借助循环依次处理向量中的每个元素,就相当于再套一层 for 循环。
Score_Conv2 <- function(score) {
n <- length(score)
res <- vector("character", n)
for(i in 1:n) {
if(score[i] >= 90) {
res[i] = "优"
} else if(score[i] >= 80) {
res[i] = "良"
} else if(score[i] >= 70) {
res[i] = "中"
} else if(score[i] >= 60) {
res[i] = "及格"
} else {
res = "不及格"
}
}
res
}注:使用for 循环,建议提前为保存每次迭代结果设置好容器,效率更高,更多细节见
张敬信:【R语言】R语言中的循环
调用函数测试,
scores <- c(35, 67, 78, 100)
Score_Conv2(scores)
(2)借助 apply 或 map 族
简单的循环语句,基本都可以改用 apply 或 map 族函数实现,其作用相当于是依次”应用(映射)“某函数,到向量的每个元素上。
也就是说,不需要修改原函数,直接就能实现向量化操作。
这里用更先进的 map 族,更多 apply 和 map族细节同样见前面的链接文章。
library(purrr) # 用map族函数,需要加载包
scores <- c(35, 67, 78, 100)
map(scores, Score_Conv) # 映射成列表
map_chr(scores, Score_Conv) # 映射成字符串向量

6. 处理多个返回值
若自定义函数需要有多个返回值,R语言的处理方法是,将多个返回值放入一个列表,再返回一个列表。
例如,自定义函数,实现计算一个数值向量的均值和标准差。
MeanStd <- function(x)
{
mu <- mean(x)
std <- sqrt(sum((x-mu)^2) / (length(x)-1))
list(mu=mu, std=std)
}测试函数,
x <- c(2,6,4,9,12)
MeanStd(x)
7. 默认参数值
有时候需要为输入参数设置默认值。
以前面的计算数值向量的均值和标准差的函数为例。我们知道,标准差的计算公式有两种形式,一种是除以 , 一种是除以
. 此时,没有必要写两个版本的函数,只需要再增加一个指示参数,将用的多的版本设为默认即可。
MeanStd2 <- function(x, type=1) {
mu <- mean(x)
if(type==1) {
std <- sqrt(sum((x-mu)^2) / (length(x)-1))
} else {
std <- sqrt(sum((x-mu)^2) / length(x))
}
list(mu=mu, std=std)
}测试函数,
x <- c(2,6,4,9,12)
MeanStd2(x) # 同 MeanStd(x)
MeanStd2(x,2)

——————————————————————————
原创作品,版权所有,转载请注明。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3118678/ ,如需转载,请注明出处,否则将追究法律责任。