第10章 常用函数

10.1 seq()函数

seq()函数用于生成一组数字序列,seq代表sequence。参数包括:

  • from数字序列起点,默认为1。
  • to数字序列终点。
  • by步长,可以为正数、负数或者小数。
  • length.out生成数字序列的长度。
  • along.with生成与目标序列相同长度的数字序列。
  • # 从0开始,在[0,6]范围内生成以3为步长的数字序列
    seq(from=0, to=6, by=3) 
    ## [1] 0 3 6
    # 超出范围的数字将不会被纳入到数字序列中
    seq(from=1, to=6, by=3) 
    ## [1] 1 4
    # 从0开始,以3为步长,生成一个包含4个元素的数字序列
    seq(from=0, by=3, length.out=4) 
    ## [1] 0 3 6 9
    # 从1开始,以2为步长,生成一个与month.abb相同长度的数字序列
    seq(from=1, by=2, along.with=month.abb) 
    ##  [1]  1  3  5  7  9 11 13 15 17 19 21 23

    10.2 rep()函数

    rep()函数用于生成重复序列,rep代表repeat。参数包括:

  • x想要进行复制的对象,可以是一个数字,字符或者向量。
  • times对整个目标对象复制的次数,只能为正整数。
  • each对目标对象内元素复制的次数,只能为正整数。
  • length.out生成序列的长度。
  • # 对向量c(1,2,3)复制2次
    rep(1:3, times=3)
    ## [1] 1 2 3 1 2 3 1 2 3
    # 对向量c(1,2,3)内的元素分别复制3、2、1次
    rep(1:3, times=c(3,2,1)) 
    ## [1] 1 1 1 2 2 3
    # 对向量c(1,2,3)内的元素各复制2次
    rep(1:3, each=2) 
    ## [1] 1 1 2 2 3 3
    # 超过的长度自动截断
    rep(c("abc", "bbb"), time=3, length.out=3) 
    ## [1] "abc" "bbb" "abc"
    # 不足的长度自动填补
    rep(c("abc", "bbb"), time=3, length.out=9) 
    ## [1] "abc" "bbb" "abc" "bbb" "abc" "bbb" "abc" "bbb" "abc"

    10.3 unique()函数

    unique()函数用于移除重复值。

    unique(c(1,2,2,3,4,3,2))
    ## [1] 1 2 3 4

    10.4 quantile()函数

    quantile()函数用于获取分位数。

    # 获取上下四分位数以及中位数
    quantile(seq(0,1,0.05), probs=c(0.25,0.5,0.75))
    ##  25%  50%  75% 
    ## 0.25 0.50 0.75

    10.5 floor()、ceiling()、round()函数

    有时我们需要对小数进行处理。
  • floor()函数返回不大于当前数字的最大整数,实际操作为提取数字的整数部分。
  • ceiling()函数返回不小于于当前数字的最小整数,实际操作为提取数字的整数部分再加1
  • round()函数用于四舍五入至特定小数位。
  • num_demo <- 3.1415926
    floor(num_demo)
    ## [1] 3
    ceiling(num_demo)
    ## [1] 4
    round(num_demo, 3)
    ## [1] 3.142

    10.6 sample()函数

    sample()函数用于随机抽样。参数包括:

  • x想要进行抽样的向量。
  • size想要进行抽样的向量。
  • replace默认为FALSE,即不重复抽样,此时size不能大于x。若为TRUE,则为重复抽样,此时size可以大于x
  • prob向量中各元素被抽到的概率,默认为NULL,即概率相同。
  • 注意:在进行随机抽样前,使用 set.seed() 函数设置随机种子可以保证抽样结果的复现。随机种子的赋值只需初始化一次。

    # set.seed(1)
    sample(1:6, size=10, replace=TRUE) # 从[1,6]中重复地随机抽取10个元素
    ##  [1] 3 4 4 5 2 4 4 3 2 5

    10.7 combn()函数

    combn()函数用于获得目标向量中指定长度的所有组合,常用于需要遍历变量组合的情况。参数包括:

  • x目标向量。
  • m指定组合长度。
  • simplify默认为TRUE,即返回矩阵。若为FALSE,则返回列表。
  • # 创建向量
    var_list <- c("bmi", "age", "sex", "education") 
    
    # 将var_list内的三个元素随机组合,返回为矩阵
    combn(var_list, 3) 
    ##      [,1]  [,2]        [,3]        [,4]       
    ## [1,] "bmi" "bmi"       "bmi"       "age"      
    ## [2,] "age" "age"       "sex"       "sex"      
    ## [3,] "sex" "education" "education" "education"
    # 获取返回矩阵的第一个组合
    combn(var_list, 3)[,1] 
    ## [1] "bmi" "age" "sex"
    # 将变量var_list内的三个元素随机组合,返回为列表
    combn(var_list, 3, simplify=FALSE) 
    ## [[1]]
    ## [1] "bmi" "age" "sex"
    ## 
    ## [[2]]
    ## [1] "bmi"       "age"       "education"
    ## 
    ## [[3]]
    ## [1] "bmi"       "sex"       "education"
    ## 
    ## [[4]]
    ## [1] "age"       "sex"       "education"
    # 获取返回列表的第一个组合
    combn(var_list, 3, simplify=FALSE)[[1]] 
    ## [1] "bmi" "age" "sex"

    10.8 paste()函数

    paste()函数用于将向量、数字或字符合并成字符串,常用于特定语句的生成。

  • sep参数用于定义将不同向量或字符合并成字符串所用的连接符。
  • collapse参数用于定义将单一向量内元素合并成字符串所用的连接符。
  • # 将不同向量或字符合并成字符串
    paste("are", "you", "OK", sep=" ") # 返回一个字符串
    ## [1] "are you OK"
    paste0("are", "you", "OK") # paste0()与paste(sep="")一样
    ## [1] "areyouOK"
    paste(var_list, "cn", sep="-") # 返回包含字符串的向量
    ## [1] "bmi-cn"       "age-cn"       "sex-cn"       "education-cn"
    # 将单一向量内元素合并成字符串
    paste(var_list, collapse="+") # 返回一个字符串
    ## [1] "bmi+age+sex+education"

    10.9 ifelse()函数

    ifelse()函数为条件函数,包含三个参数:

  • test条件。
  • yes条件为TRUE时的返回值。
  • no条件为FALSE时的返回值。
  • 此函数在条件判断中可以得到多个逻辑结果,返回对应数目的逻辑值并根据逻辑值赋值(注意与if(){}else{}函数[小节10.10]的区别)。此函数可以嵌套。

    # 创建向量
    age <- seq(1,4)
    target <- c(2,2,4,4)
    
    # ifelse可进行多个逻辑判断并分别返回值
    ifelse(age==target, "Y", "N") 
    ## [1] "N" "Y" "N" "Y"
    ifelse(age==1, "age1", ifelse(age<4, "age2", "age3"))
    ## [1] "age1" "age2" "age2" "age3"

    10.10 if(){}else{}函数

    ()内为判断条件,如果为真,则运行第一个{}的指令,否则运行第二个{}的指令。此判断条件中只接受一个逻辑结果。如果输入多个逻辑结果,将会报错,此时需要用any()或者all()函数对多个逻辑结果进行处理。使用多个else if(){}进行嵌套。

    注意与ifelse()函数[小节10.9]的区别。

    # if(){}else{}只接受一个逻辑值
    if(any(age==c(1,1,1,1))){"Y"} else{"N"}
    ## [1] "Y"
    # 创建向量
    new_age <- 55
    
    if(new_age<40){
      "青年"
    } else if(new_age<60){
      "中年"
    } else {"老年"}
    ## [1] "中年"

    10.11 循环

    10.11.1 for循环

    for循环是R语言中最常用的迭代函数之一,形式为for(){}

  • ()内为迭代器,即需要迭代的向量。
  • {}内为想要运行的指令。
  • for(i in seq(1:4)){
      print(paste0("现在的数字是:", i)) # 循环打印
    }
    ## [1] "现在的数字是:1"
    ## [1] "现在的数字是:2"
    ## [1] "现在的数字是:3"
    ## [1] "现在的数字是:4"
    ini_num <- 5 # 设定初始值
    sum_container <- c() # 创建空向量
    for(i in seq(1,5,by=2)){
      ini_num = ini_num + i # 迭代求和
      sum_container <- append(sum_container, ini_num) # 将求和值添加入向量
    }
    sum_container
    ## [1]  6  9 14

    10.11.2 while循环

    while(){}循环将重复执行{}中的指令直至不能满足()中的条件。

    init_num <- 0 # 设定初始值
    while(init_num<4){
      init_num = init_num + 1 # 每次计数+1
      print(paste0("已完成", init_num, "次运算。"))
    }
    ## [1] "已完成1次运算。"
    ## [1] "已完成2次运算。"
    ## [1] "已完成3次运算。"
    ## [1] "已完成4次运算。"

    10.11.3 apply()函数

    当需要对矩阵或者数据框进行统一的特定处理时,为避免重复使用循环,可以选择apply()函数,返回类型为向量或矩阵。此函数中三个主要的参数为:

  • X输入数据。
  • MARGIN指令执行方向。
  • FUN执行指令。
  • FUN MARGIN 指令执行说明
    当指令需要作用于多个元素 MARGIN=1 逐行运行指令,返回向量
    当指令需要作用于多个元素 MARGIN=2 逐列运行指令,返回向量
    当指令只作用于单个元素 MARGIN=1 逐个运行指令,返回矩阵。可以理解为将数据转置后对单个元素进行处理。
    当指令只作用于单个元素 MARGIN=2 逐个运行指令,返回矩阵。可以理解为在原有数据上直接对单个元素进行处理。
    # apply()函数与矩阵
    var_matrix <- matrix(c(1,4,9,16,25,36),nrow=2)
    
    # 指令作用于多个元素
    apply(var_matrix, 1, sum) 
    ## [1] 35 56
    # 指令作用于多个元素
    apply(var_matrix, 2, sum) 
    ## [1]  5 25 61
    # 指令作用于单个元素
    apply(var_matrix, 1, sqrt) 
    ##      [,1] [,2]
    ## [1,]    1    2
    ## [2,]    3    4
    ## [3,]    5    6
    # 指令作用于单个元素
    apply(var_matrix, 2, sqrt) 
    ##      [,1] [,2] [,3]
    ## [1,]    1    3    5
    ## [2,]    2    4    6
    # apply()函数与数据框
    # 读取数据
    data(iris)
    
    # 对iris数据库中的第1、3列分别求和
    apply(iris[,c(1,3)], 2, sum) 
    ## Sepal.Length Petal.Length 
    ##        876.5        563.7

    当需要对列表或数据框进行统一的特定处理时,可以使用lapply()函数,返回类型为列表。主要参数为X即输入数据和FUN执行指令。当FUN作用于X内的单个元素时,X的结构不会发生改变。

    var_vector_list <- list(c(1,4,9), c(16,25,36))
    lapply(var_vector_list, sum) 
    ## [[1]]
    ## [1] 14
    ## 
    ## [[2]]
    ## [1] 77
    # 函数作用于单个元素时,元素结构不会发生改变
    lapply(var_vector_list, sqrt) 
    ## [[1]]
    ## [1] 1 2 3
    ## 
    ## [[2]]
    ## [1] 4 5 6
    var_matrix_list <- list(matrix(c(1,4,9,16,25,36),nrow=2),matrix(c(1,4,9,16,25,36),nrow=2))
    lapply(var_matrix_list, sum) 
    ## [[1]]
    ## [1] 91
    ## 
    ## [[2]]
    ## [1] 91
    # 函数作用于单个元素时,元素结构不会发生改变
    lapply(var_matrix_list, sqrt) 
    ## [[1]]
    ##      [,1] [,2] [,3]
    ## [1,]    1    3    5
    ## [2,]    2    4    6
    ## 
    ## [[2]]
    ##      [,1] [,2] [,3]
    ## [1,]    1    3    5
    ## [2,]    2    4    6

    当需要对列表、向量或数据框进行统一的特定处理且希望返回最简单的数据结构时,可以使用sapply()函数。

    var_matrix <- matrix(c(1,4,9,16,25,36),nrow=2)
    sapply(var_matrix, sum) # 返回向量
    ## [1]  1  4  9 16 25 36
    sapply(var_matrix, sqrt) # 返回向量
    ## [1] 1 2 3 4 5 6
    var_vector_list <- list(c(1,4,9), c(16,25,36))
    sapply(var_vector_list, sum) # 返回向量
    ## [1] 14 77
    sapply(var_vector_list, sqrt) # 返回矩阵
    ##      [,1] [,2]
    ## [1,]    1    4
    ## [2,]    2    5
    ## [3,]    3    6
    var_matrix_list <- list(matrix(c(1,4,9,16,25,36),nrow=2),matrix(c(1,4,9,16,25,36),nrow=2))
    sapply(var_vector_list, sum) # 返回向量
    ## [1] 14 77
    sapply(var_matrix_list, sqrt) # 返回矩阵
    ##      [,1] [,2]
    ## [1,]    1    1
    ## [2,]    2    2
    ## [3,]    3    3
    ## [4,]    4    4
    ## [5,]    5    5
    ## [6,]    6    6

    当需要对向量按类别进行统一的特定处理时,可以使用tapply()函数,返回数组。

    data(iris)
    tapply(iris[,1], iris$Species, mean)
    ##     setosa versicolor  virginica 
    ##      5.006      5.936      6.588

    小结

    函数 主要参数 输入数据类型 输出数据类型
    apply apply(X,MARGIN,FUN) 矩阵、数据框 向量、矩阵
    lapply lapply(X,FUN) 列表、数据框 列表
    sapply sapply(X,FUN) 列表、矩阵、数据框 向量、矩阵
    tapply tapply(X,INDEX,FUN) 向量 数组

    10.12 自定义函数

    function(){}用于自定义函数,其中()用于定义函数的参数,{}用于定义函数的指令并以return()定义要返回的数据。

    # 定义一个函数,用于报告向量长度
    length_report <- function(x){
      print(paste0("此向量的长度是:", length(x)))
    }
    
    length_report(c("bmi", "grip", "sex", "age"))
    ## [1] "此向量的长度是:4"
    # 定义一个x+2y的函数,返回运算结果
    multiply_function <- function(x,y){
      return(x+2*y)
    }
    
    result_multiply <- multiply_function(2,3) # 传入参数位置与函数参数位置对应
    result_multiply
    ## [1] 8
    # 定义默认变量
    multiply_function2 <- function(x,y,z="运算完成!"){
      print(z)
      return(x+2*y)
    }
    
    multiply_function2(2,3)
    ## [1] "运算完成!"
    ## [1] 8
    multiply_function2(2,3,"哈哈,运算完成~")
    ## [1] "哈哈,运算完成~"
    ## [1] 8

    函数只能返回一个结果,所以,如果有多个结果需要返回时,可以将结果整合为向量、列表或者数据框的形式之后再返回。

    # 定义一个函数,获取向量内个元素累计叠加的值
    accumulation <- function(x){
      init_num <- x[1] # 获取第1个元素
      result <- c(init_num) # 建立result向量收集结果
      if (length(x)>=2){
        for(i in seq(2,length(x))) {
          init_num <- init_num + x[i]
          result <- append(result, init_num)
        }
      }
      return(result) # 返回向量
    }
    
    accumulation(seq(1:4))
    ## [1]  1  3  6 10
    # 方法2:使用while循环
    accumulation2 <- function(x){
      init_num <- x[1]
      vec_length <- length(x) 
      result <- c(init_num)
      while(vec_length>1){
        vec_length <- vec_length - 1
        init_num <- init_num + x[length(x)-vec_length+1]
        result <- append(result, init_num)
      }
      return(result)
    }
    
    accumulation2(seq(1:4))
    ## [1]  1  3  6 10