搜索
查看: 429|回复: 0

[R] 慧美——R for data science 第14章 函数

[复制链接]

26

主题

27

帖子

241

积分

中级会员

Rank: 3Rank: 3

积分
241
发表于 2018-11-28 15:25:40 | 显示全部楼层 |阅读模式
R for data science  第14章 函数
14.1 简介
  • 函数具有以下 3 个主要优点。
    • 可以给函数起一个意味深长的名字,从而让代码更容易理解。
    • 如果需求发生了变化,只需要修改一处代码即可,无须修改多处。
    • 消除了复制粘贴时可能出现的无心之失(比如,修改了一处的变量名称,但却没有修改另一处)。


14.2 什么时候应该使用函数
  • 要想创建一个新函数,需要以下 3 个关键步骤
    • 为函数选择一个名称。
    • 列举出 function 中所用的输入,即参数。
    • 将已经编写好的代码放在函数体中。在 function(...) 后面要紧跟一个用 {} 括起来的代码块。

  • 确定函数如何使用简单输入来运行后,我们才开始编写函数。从工作代码开始,再将其转换为函数

14.3 人与计算机的函数
  • 函数名
    • 理想的函数名应该既简短,又能清楚地说明函数的作用
    • 函数名应该是动词,而参数名应该是名词。但也有例外:如果函数计算的是一 个众所周知的名词(比如,mean() 要比 compute_mean() 好),或者读取的是对象的某种属性 (比如,coef() 要比 get_coefficients() 好)时,那么函数名使用名词也是可以的
    • 如果你的函数名由多个单词组成,那么我们建议用“snake_case”命名法,即使用小写单词,单词之间用下划线隔开。另一种常用的命名法是“camelCase”,即首个单词小写,其余单词首字母大写。
    • 如果你有一族功能相似的函数,那么一定要确保它们具有一致的名称和参数。可以使用一个通用前缀来表明它们之间的联系,这种方式比使用通用后缀更好,因为如果 IDE 有自动完成功能,那么就可以在输入前缀后列举出这个函数族中的所有成员
    • 应该使用注释(即由 # 开头的行)来解释代码,需要解释的是“为什么”
    • RStudio 提供了键盘快捷方式来创建这种分节标记,即 Ctrl+Shift+R,并且可以在脚本编辑器左下角的代码浏览弹出菜单中显示这些标记


file:///Users/huimei/Library/Application%20Support/typora-user-images/image-20181128084614308.png?lastModify=1543389899
14.4 条件执行
  • if 语句可以使得你有条件地执行代码

if(condition) {
# 条件为真时执行的代码
  } else{
# 条件为假时执行的代码 }
  • 要想获得有关 if 语句的帮助,你需要使用反引号将其括起来:?if

  • condition 的值要么是 TRUE,要么是 FALSE。如果它是一个向量,那么你会收到一条警告; 如果它是 NA,那么程序就会出错。

  • 可以使用 ||(或)和 &&(与)操作符来组合多个逻辑表达式。不能在 if 语句中使用 | 或 &,它们是向量化的操作符,只可以用于多个值(这就是我们在 filter() 函数中使用它们的原因)。如果一定要使用逻辑向量,那么你可以使用 any() 或 all() 函数将其转换为单个逻辑值。

  • 多重条件

if(this) {
# 做一些操作
} elseif(that) { # 做另外一些操作
} else{
#
}
  • 果你有一长串 if 语句,那么就要考虑重写了。重写的一种方法是使用 switch() 函数,它先对第一个参数求值,然后按照名称或位置在后面的参数列表中匹配返回结果

#> function(x, y, op) {
#>   switch(op,
#>
#>
#>
#>
#>
#>   )
#> }
plus=x+y,
minus=x-y,
times=x*y,
divide=x/y,
stop("Unknown op!")
  • 代码风格
    • if 和 function 后面总是要跟着一对大括号({}),其中的内容应该缩进两个空格。这样通过左侧空白就可以很容易地知道代码层次。
    • 左大括号不应该自己占一行,而且后面要换行。右大括号应该自己占一行,除非后面跟着else。大括号中的代码一定要缩进


  • 如果 if 语句非常短,可以在一行内写下,那么可以不用大括号

14.5 函数参数
  • 函数的参数通常分为两大类:一类提供需要进行计算的数据,另一类控制计算过程的细节。

  • 数据参数应该放在最前面,细节参数则放在后面,而且一般都有默认值。设置默认值的方式与使用命名参数调用函数的方式是一样的

  • 默认值应该几乎总是最常用的值。 通过默认设置忽略缺失值不是好做法。na.rm = TRUE

  • 在调用函数时,应该在其中 = 的两端都加一个空格。逗号后面应该总是加一个空格,逗号前面则不要加空格(与英文写法相同)。使用空格可以使得函数的重要部分更易读

  • 选择参数名称
    • 通常应该选择那些较长的、更具描述性的名称
    • 记住短短通用名称
      • x, y, z:向量
      • w:权重向量
      • df:数据框
      • i, j:数值索引(通常用于表示行和列)。
      • n:长度或行的数量
      • p:列的数量



  • 检查参数值
    • 当编写的函数越来越多时,你有时会记不清某个函数到底是用来做什么的。这时就很容易使用无效的参数来调用函数。为了解决这种问题,应该对函数参数进行明确的限制。对重要的前提条件进行检查,当其不为真时就抛出一个错误(使用 stop() 函数)


  • 点点点(...)
    • R 中的很多函数可以接受任意数量的输入,...(读作点点点)。这个特殊参数会捕获任意数量的未匹配参数。因为你可以将它捕获的值传给另一个函数。
    • 然非常方便,但这种技术是有代价的:所有拼写错误的参数都不会引发错误消息。这使得我们很难发现输入错误
    • 如果想要检查 ... 中的值,那么你可以使用 list(...)。

  • 惰性求值
    • R 中的参数求值的方式是惰性的,即直到需要参数时才会进行求值。

    14.6 返回值
  • 对于返回值,以下两个问题需要你仔细思考
    • 提前返回能否让函数更易读?
    • 你能使得自己的函数支持管道操作吗?

  • 显式返回语句
    • 函数的返回值通常是最后一个语句的值,但你可以通过 return() 语句提前返回一个值。常见的提前返回原因就是输入为空
    • 需要提前返回的另一个原因是,if 语句的一个分支非常复杂,而另一个分支则特别简单。但如果第一个分支中的代码非常长,到达 else 语句前,你可能就已经记不清 condition了。解决这个问题的一种方法是将简单情形提前返回。

  • 使得函数支持管道
    • 可以支持管道操作的函数有两种主要类型:转换函数与副作用函数。
      • 转换函数会传入一个明确的“基本”对象作为第一个参数,对这个对象进行处理后,再将 其返回。 如果能够确定该使用哪种数据类型,就可以让自己的函数支持管道操作了。
      • 副作用函数经常用来执行某种行为,比如绘图或保存文件,而不是转换对象。这些函数会 “悄悄地”返回第一个参数,因此,默认情况下,第一个参数不显示在输出中,但仍然可以由管道操作使用。



14.7 环境
  • 函数的环境决定了 R 如何寻找对象的值。

  • R 使用称为词法定界的一种规则来搜索对象的值。因为 y 没有在函数中进行定义,所以 R 会在定义函数的环境中寻找 y




上一篇:慧美——R for data science 第13章 使用magrittr进行管道操作
下一篇:gdc-client安装报错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|生信技能树 ( 粤ICP备15016384号  

GMT+8, 2019-7-24 02:36 , Processed in 0.028940 second(s), 26 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.