5.5 用户自编函数

R的最大优点之一就是用户可以自行添加函数。事实上,R中的许多函数都是由已有函数构成的。一个函数的结构看起来大致如此:

  1. myfunction <- function(arg1, arg2, ... ){
  2. statements
  3. return(object)
  4. }

函数中的对象只在函数内部使用。返回对象的数据类型是任意的,从标量到列表皆可。让我们看一个示例。

假设你想编写一个函数,用来计算数据对象的集中趋势和散布情况。此函数应当可以选择性地给出参数统计量(均值和标准差)和非参数统计量(中位数和绝对中位差)。结果应当以一个含名称列表的形式给出。另外,用户应当可以选择是否自动输出结果。除非另外指定,否则此函数的默认行为应当是计算参数统计量并且不输出结果。代码清单5-8给出了一种解答。

代码清单5-8 mystats():一个由用户编写的描述性统计量计算函数

  1. mystats <- function(x, parametric=TRUE, print=FALSE) {
  2. if (parametric) {
  3. center <- mean(x); spread <- sd(x)
  4. } else {
  5. center <- median(x); spread <- mad(x)
  6. }
  7. if (print & parametric) {
  8. cat("Mean=", center, "\n", "SD=", spread, "\n")
  9. } else if (print & !parametric) {
  10. cat("Median=", center, "\n", "MAD=", spread, "\n")
  11. }
  12. result <- list(center=center, spread=spread)
  13. return(result)
  14. }

要看此函数的实战情况,首先需要生成一些数据(服从正态分布的,大小为500的随机样本):

  1. set.seed(1234)
  2. x <- rnorm(500)

在执行语句:

  1. y <- mystats(x)

之后,y$center将包含均值(0.00184),y$spread将包含标准差(1.03),并且没有输出结果。如果执行语句:

  1. y <- mystats(x, parametric=FALSE, print=TRUE)

y$center将包含中位数(–0.0207),y$spread将包含绝对中位差(1.001)。另外,还会输出以下结果:

  1. Median= -0.0207
  2. MAD= 1

下面让我们看一个使用了switch结构的用户自编函数,此函数可让用户选择输出当天日期的格式。在函数声明中为参数指定的值将作为其默认值。在函数mydate()中,如果未指定type,则long将为默认的日期格式:

  1. mydate <- function(type="long") {
  2. switch(type,
  3. long = format(Sys.time(), "%A %B %d %Y"),
  4. short = format(Sys.time(), "%m-%d-%y"),
  5. cat(type, "is not a recognized type\n")
  6. )
  7. }

实战中的函数如下:

  1. > mydate("long")
  2. [1] "Thursday December 02 2010"
  3. > mydate("short")
  4. [1] "12-02-10"
  5. > mydate()
  6. [1] "Thursday December 02 2010"
  7. > mydate("medium")
  8. medium is not a recognized type

请注意,函数cat()仅会在输入的日期格式类型不匹配"long""short"时执行。使用一个表达式来捕获错误输入的参数值通常来说是一个好主意。

有若干函数可以用来为函数添加错误捕获和纠正功能。你可以使用函数warning()来生成一条错误提示信息,用message()来生成一条诊断信息,或用stop()停止当前表达式的执行并提示错误。请参阅每个函数的在线帮助文档以了解详细用法。

小提示 一旦开始编写无论任何长度和复杂度的函数,优秀调试工具的重要性都会凸显出来。R中有许多实用的内建调试函数,也有许多用户贡献包提供了额外的功能。关于这个话题,一份优秀的参考资料是Duncan Murdoch整理的“Debugging in R”(http://www.stats.uwo.ca/faculty/murdoch/software/debuggingR)。

在创建好自己的函数以后,你可能希望在每个会话中都能直接使用它们。附录B描述了如何定制R环境,以使R启动时自动读取用户编写的函数。我们将在第6章和第8章中看到更多的用户自编函数示例。

你可以使用本节中提供的基本技术完成很多工作。如果你想要探索编写函数的微妙之处,或编写可以分发给他人使用的专业级代码,个人推荐两本优秀的书籍,你可在本书末尾的参考文献部分找到:Venables & Ripley(2000)以及Chambers(2008)。这两本书共同提供了大量细节和众多示例。

函数的编写就讲到这里,我们将以对数据整合和重塑的讨论来结束本章。