R for data Science(十三)

作者: 一路向前_莫问前程_前程似锦 | 来源:发表于2018-09-08 20:19 被阅读5次

    编写函数

    Code style

    一般function后面都会有一个花括号{},用于填函数体,但是如果if 语句后面的函数句太短的时候,可以省略花括号:
    如下:
    y <- 10
    x <- if (y < 20) "Too low" else "Too high"
    
    书的作者只推荐非常简短的if语句。否则,还是要用完整的花括号来更容易阅读
    if (y < 20) {  x <- "Too low" } else {  x <- "Too high"}
    

    Function arguments

    函数的参数通常分为两大类:一组提供要计算的数据,另一组提供控制计算细节的参数。(data,detail)
    例如:
    在log()中,数据是x,而detail是对数的底。
    在mean()中,数据是x,而细节是从结束(修剪)和如何处理缺失值(na.rm)中裁剪多少数据。
    在t.test()中,数据是x和y,测试的细节是alternative, mu, paired, var.equal, 和 conf.level。
    在str_c()中,您可以向…提供任意数量的字符串。,连接的细节由sep和collapse控制。
    通常,数据参数应该放在首位。细节参数应该在末尾,并且通常应该具有默认值。您指定一个默认值的方式与使用命名参数调用函数的方式相同
    # Compute confidence interval around mean using normal approximation
    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)
    #> [1] 0.498 0.610
    mean_ci(x, conf = 0.99)
    #> [1] 0.480 0.628
    
    当您调用一个函数时,您通常会忽略数据参数的名称,因为它们非常常用。如果重写细节参数的默认值,应该使用参数全名:
    # Goodmean(1:10, na.rm = TRUE)##下面的形式就不友好# Badmean(x = 1:10, , FALSE)mean(, TRUE, x = c(1:10, NA))
    

    Checking values

    当你开始写更多的函数时,你最终会忘记你的函数是如何工作的。此时,使用无效的输入调用函数很容易。为了避免这个问题,明确约束通常是有用的。例如,假设您编写了一些计算加权汇总统计的函数。
    wt_mean <- function(x, w)
     {  sum(x * w) / sum(w)}
    wt_var <- function(x, w)
     {  mu <- wt_mean(x, w)  sum(w * (x - mu) ^ 2) / sum(w)}
    wt_sd <- function(x, w)
     {  sqrt(wt_var(x, w))}
    
    你会发现x和w长度不同,但是R里面不会报错,因为R里面可以增加循环
    wt_mean(1:6, 1:3)
    #> [1] 7.67
    

    It’s good practice to check important preconditions, and throw an error (with stop()), if they are not true:

    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(w)}
    
    image
    如果你也加了一个na.rm参数,你可能不会仔细检查。
    wt_mean <- function(x, w, na.rm = FALSE) {
      if (!is.logical(na.rm))
     {    stop("`na.rm` must be logical")  }  
    if (length(na.rm) != 1) {    stop("`na.rm` must be length 1")  }
      if (length(x) != length(w))
     {    stop("`x` and `w` must be the same length", call. = FALSE)  }  
    if (na.rm) {    miss <- is.na(x) | is.na(w)    x <- x[!miss]    w <- w[!miss] 
     }
      sum(w * x) / sum(w)}
    
    这是很多额外的工作,几乎没有额外的收获。一个有用的折衷方案是内置的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(w)}
    wt_mean(1:6, 6:1, na.rm = "foo")
    #> Error in wt_mean(1:6, 6:1, na.rm = "foo"): is.logical(na.rm) is not TRUE
    
    image

    Return values

    函数返回的值通常是它计算的最后一个语句,但是您可以使用return()选择返回之前的值。作者认为最好保存return()的使用,以表明您可以使用更简单的解决方案提前返回。
    complicated_function <- function(x, y, z) {  
    if (length(x) == 0 || length(y) == 0)
     {    return(0)  } 
     # Complicated code here}
    
    当你有一个if语句,包含一个复杂块和一个简单块。例如,您可以编写这样的if语句
    f <- function() { 
     if (x) {
        # Do     # something    # that    # takes    # many    # lines    # to    # express  }
     else {    # return something short  
    }}
    
    但是如果第一个代码块很长,当你写到else,你已经忘记了条件。那么你可以以一种简单的方式重写:
    f <- function() {
      if (!x) {  
      return(something_short) 
     }  # Do   # something  # that  # takes  # many  # lines  # to  # express}
    

    相关文章

      网友评论

        本文标题:R for data Science(十三)

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