美文网首页R语言
function()编写函数

function()编写函数

作者: 小贝学生信 | 来源:发表于2020-06-14 14:14 被阅读0次

之前在R语言入门--第四节(数据管理进阶)笔记的最后部分以两个例子简单学习了利用function()自定义编写函数的方法,这次专门再学习下。

自定义函数的目的主要是为了简化代码。有人曾说只要一段代码需要复制粘贴的次数超过两次(也就是说,同一段代码至少有 3 个副本),那么就应该考虑编写一个函数。

一、function编写步骤

1、为函数选择一个合适的名称

  • 最好是动词,描述函数的功能;
  • 多个单词时,用连接符,如_.等,选择自己常用的,保持自己的风格;
  • 有一族功能相似的函数,那么一定要确保它们具有一致的名称和参数,例如相同的前缀。

2、列举出 function 中所用的输入

  • 编写时逻辑要清晰,理解这个函数的输入与输出;输入即是函数的参数;
  • 格式上为function后()里的部分;
  • 一般函数的参数可分为两类---数据与细节调节。具体后面会介绍。

3、将已经编写好的代码放在函数体中

  • 格式上为紧跟function()后{}里的代码块;
  • 左大括号不应该自己占一行,而且后面要换行。右大括号应该自己占一行,除非后面跟着else。
  • 大括号中的代码一定要缩进,一般都会自动缩进的。

例子

函数功能:将数据中心化为0~1区间

rescale01 <- function(x) {
rng <- range(x, na.rm = TRUE)
# 中间计算结果保存为命名变量是一种非常好的做法,因为这样可以让代码的意义更加清楚。
(x - rng[1]) / (rng[2] - rng[1])
}
rescale01(c(0, 5, 10))
df <- data.frame(
  a = rnorm(10),
  b = rnorm(10),
  c = rnorm(10),
  d = rnorm(10)
)
rescale01(df$a)

当函数复杂时,可利用#加入注释,便于他人或者将来自己的理解。此外也可创建分节标记,快捷键Ctrl+Shift+R,方便代码管理。

二、常见搭配--if条件语句

  • 当函数执行多种复杂功能时,尤其是有多个参数或者参数有多个选项时,则必须用到if条件语句。(可以参看开头那个链接笔记)
  • 基本框架--
if (condition) {
  # 条件为真时执行的代码
} else {
  # 条件为假时执行的代码
}

注意点

  • condition逻辑表达式的值要么是 TRUE ,要么是 FALSE

在测试相等关系时,一定要小心, == 是向量化的,很容易输出多个值,即要先检查长度是否相同。或者推荐使用非向量化的identical() 函数。 identical() 非常严格,总是返回一个 TRUE 或者一个 FALSE ,并且不限制参数类型。

  • 当需要多个表达式一起决定时,可根据情况选择II(或)、&&(与)操作符。

教材说不能用|&,但我看链接笔记里也确实用到了&结构,存疑!

  • 当参数有多个选项时,可使用switch()函数,可参见链接笔记第二个例子。或者见下
compute <- function(x, y, op) {
switch(op,
 plus = x + y,
 minus = x - y,
 times = x * y,
 divide = x / y,
 stop("Unknown op!")
) 
}
compute(1, 2, "pus")

三、函数参数

1、参数分类

如前所述函数的参数通常分为两大类:一类提供需要进行计算的数据,另一类控制计算过程的细节。举例----

  • 在 mean() 函数中,数据是 x ,细节则是从x 前后两端( trim )移除多大比例的数据,以及如何处理缺失值( na.rm )。
  • 在 t.test() 函数中,数据是 x 和y ,检验的细节则是 alternative 、 mu 、 paired 、 var.equal 以及 conf.level 等设置。

2、特殊的数据参数

  • ... 三个点表示可提供任意数量的字符串作为数据,即捕获到任意数量的未匹配参数。注意是未匹配的参数!
?sum
sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
?stringr::str_c
stringr::str_c("a", "b", "c", "d", "e", "f")

3、设置默认细节调节参数

  • 数据参数应该放在最前面,细节参数则放在后面,而且一般都有默认值。
  • 设置默认值的方式与使用命名参数调用函数的方式是一样的,在括号内设置好即可。
# 使用近似正态分布计算均值两端的置信区间
mean_ci <- function(x, conf = 0.95) {
  se <- sd(x) / sqrt(length(x))
  alpha <- 1 - conf
  mean(x) + se * qnorm(c(alpha / 2, 1 - alpha / 2))
}

x <- runif(100)
mean_ci(x)
mean_ci(x, conf = 0.99)

调用函数时,最好遵循参数的书写格式。即在其中 = 的两端都加一个空格。逗号后面应该总是加一个空格,逗号前面则不要加空格。此外值得注意的一点是我们经常省略数据参数的名称。

4、检查参数值

  • 使函数使用更加友好,应该事先检查参数的有效性。
  • 若不符合既定要求,则返回提示性报错。
(1)stop函数

检查一个要求时方便

wt_mean <- function(x, w) {
  if (length(x) != length(w)) {
    stop("`x` and `w` must be the same length", call. = FALSE)
  }
  sum(w * x) / sum(x)
}
wt_mean(1:5,6:10)
(2)stopifnot()函数

可检查多个参数

wt_mean <- function(x, w, na.rm = FALSE) {
  stopifnot(is.logical(na.rm), length(na.rm) == 1)
  stopifnot(length(x) == length(w))
  if (na.rm) {
    miss <- is.na(x) | is.na(w)
    x <- x[!miss]
    w <- w[!miss]
  }
  sum(w * x) / sum(x)
}
wt_mean(1:6, 6:1, na.rm = "foo")

5、常见通用参数

  • 一般参数名也是可自己任意设置,但也要有意义。
  • R 中有一些非常短的通用名称,值得我们编写函数时借鉴
    x, y, z :向量。
    w :权重向量。
    df:数据框。
    i, j :数值索引(通常用于表示行和列)。
    n :长度或行的数量。
    p :列的数量。
    na.rm:是否需要除去缺失值。

将 na.rm 的默认值设为 FALSE 是情有可原的,因为缺失值有时是非常重要的。虽然代码中经常使用的是 na.rm = TRUE ,但是通过默认设置不声不响地忽略缺失值并不是一种良好的做法。

四、函数返回值

  • 函数的返回值通常是最后一个语句的值;
  • 也可以通过 return() 语句提前返回一个值。
  • 如果函数功能能够返回多个值,那么可将结果都归为一个list列表里,最后将list导出即可。可参考开头链接笔记第一个例子。

补充:管道符

  • magrittr包的%>%函数
    关于管道符我的理解就是把左边的数据通过管道符传给右边的函数,作为其数据参数。而这个函数的处理结果,若为数据,还可继续通过管道符传给下一个函数,如此循环下去...
  • 意义在于可以在后期用于优化代码,减少不必要的中间变量。
mtcars$cyl %>%
  table() %>%
  barplot()

支持管道符的函数类型

  • 我的理解就是不修改,变动数据参数时,这些函数会“悄悄地”返回第一个参数,因此,默认情况下,第一个参数不显示在输出中,但仍然可以由管道操作使用。
  • 例如绘图、保存、统计类函数等
show_missings <- function(df) {
  n <- sum(is.na(df))
  cat("Missing values: ", n, "\n", sep = "")
  invisible(df)
}
show_missings(mtcars)
library(dplyr)
mtcars %>%
  show_missings() %>%
  mutate(mpg = ifelse(mpg < 20, NA, mpg)) %>%
  show_missings()

相关文章

  • function()编写函数

    之前在R语言入门--第四节(数据管理进阶)笔记的最后部分以两个例子简单学习了利用function()自定义编写函数...

  • Scala基础——概述

    概述 编程范式 函数式编程 就是只用纯函数(Pure function)来编写程序.纯函数:没有副作用的函数,副作...

  • 函数(有待补充)

    自定义函数 (user-defined function UDF)编写一个 SQL 查询,获取 Employee ...

  • hive窗口函数盘点

    在支持窗口函数里的sql里,善用窗口函数,能降低sql编写复杂度并提高sql执行效率。 窗口函数 function...

  • R for data Science(十三)

    编写函数 Code style 一般function后面都会有一个花括号{},用于填函数体,但是如果if 语句后面...

  • Parse Server 的云函数写法优化

    我们在使用parse server时,需要编写一些在服务器端运行的函数,也就是cloud function(云函数...

  • JS中的函数

    函数: function(){} 函数声明: function name(){ } 函数执行: name(); 函...

  • Hive | UDF

    UDF HiveQL只有几十个内嵌的函数,可以通过编写UDF(User-Defined Function)来扩展功...

  • shell函数工作实战应用

    shell函数:function函数定义:[function] funcname(){Statement;} 注意...

  • No.23 JavaScript函数

    一、函数的使用 1. 声明函数 // 声明函数function 函数名() {//函数体代码} function ...

网友评论

    本文标题:function()编写函数

    本文链接:https://www.haomeiwen.com/subject/bdritktx.html