Skip to content

sueshow/R_Basics

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 

Repository files navigation

R Basics:Apply家族

apply 家族

apply 家族位在 R 內建的 base 裡面,不需要額外安裝 package

  • apply():apply(X, MARGIN, FUN, ...)
    • apply 的用法是將一個函數 FUN 套用在指定的資料集 X 中的每個元素上,透過 MARGIN 參數來指定函數 FUN 是要依照列 (by row = 1) 還是欄 (by column = 2) 來執行
      data <- array(1:50, c(5, 10))
      apply(data, 2, function(a)sum(a^2))                       # 每一欄的平方和
      apply(data, 1, function(x) length(x[x %% 7 == 0]))        # 被 7 整除的數字個數
      
      x <- cbind(x1=3, x2=c(4:1, 2:5))
      myFUN <- function(x, c1, c2) {
                c(sum(x[c1], 1), mean(x[c2])) 
      }
      # 把數據框按行做循環,每行分別傳遞給 myFUN 函數,設置 c1,c2 對應 myFUN 的第二、三個參數
      apply(x, 1, myFUN, c1='x1', c2=c('x1','x2'))
      

      [1] 55 330 855 1630 2655 3930 5455 7230 9255 11530
      [1] 1 2 1 2 1

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
      [1,] 4.0 4 4.0 4 4.0 4 4.0 4
      [2,] 3.5 3 2.5 2 2.5 3 3.5 4


  • lapply():lapply(X, FUN, ...)
    • 透過 lapply 函數操作完之後,會回傳一個 list
    • 在 lapply 當中不能指定要 by row 還是 by column,會逐個項目去運算,所以這裡的資料 X 通常會放一維的 vector,在操作上會比較清楚
      EX1 <- lapply(1:3, function(x)x^x)                        # x 的 x 次方
      
      x <- cbind(x1=3, x2=c(2:1,4:5))
      class(x)
      lapply(x, sum)
      
      lapply(data.frame(x), sum)
      

      [1] "matrix" "array"

      [[1]] [1] 3
      [[2]] [1] 3
      [[3]] [1] 3
      [[4]] [1] 3
      [[5]] [1] 2
      [[6]] [1] 1
      [[7]] [1] 4
      [[8]] [1] 5

      $x1 [1] 12
      $x2 [1] 12


  • sapply():sapply(X, FUN, ..., simplify=TRUE, USE.NAMES=TRUE)
    • 透過函數 sapply 回傳的結果是將 list 形式簡單化 (simplified) 後的 vector
    • sapply 在功能上與 lapply 基本上是一樣的,都是餵給一個 list,然後依據後面指定的功能函數來一項一項做運算, 不過跟 lapply 不同的是,sapply 會回傳一個 vector
    • 如果 simplify=FALSE 和 USE.NAMES=FALSE,sapply 完全等於 lapply
      data2 <- data.frame(height = c(157, 172, 168),
                          weight = c(53, 70, 61))
      sapply(data2, mean)
      

      height weight
      165.66667 61.33333

      a <- 1:2
      sapply(a, function(x) matrix(x,2,2), simplify='array')
      
      sapply(a, function(x) matrix(x,2,2))
      

      , , 1
      [,1] [,2]
      [1,] 1 1
      [2,] 1 1
      , , 2
      [,1] [,2]
      [1,] 2 2
      [2,] 2 2

      [,1] [,2]
      [1,] 1 2
      [2,] 1 2
      [3,] 1 2
      [4,] 1 2


  • mapply():mapply(FUN, ..., MoreArgs=NULL, SIMPLIFY=TRUE, USE.NAMES=TRUE)
    • 可以同時使用多個變數
    • 在 mapply 中,運算函數放前,list 在後。假設今天給 mapply 三個 list{a, b, c},mapply 會分別取三個 list 的第一項去做第一次運算,然後換三個 list 的第二項去做第二次運算…依此類推
      set.seed(1)
      x <- 1:10
      y <- 5:-4
      z <- round(runif(10, -5, 5))
      # 按索引順序取較大的值
      mapply(max, x, y, z)
      

      [1] 5 4 3 4 5 6 7 8 9 10


  • vapply():vapply(X, FUN, FUN.VALUE, ..., USE.NAMES=TRUE)
    • vapply 類似於 sapply,提供 FUN.VALUE 參數,用來控制返回值的行名
      x <- data.frame(cbind(x1=3, x2=c(2:1,4:5)))
      vapply(x, cumsum, FUN.VALUE=c('a'=0, 'b'=0, 'c'=0, 'd'=0))
      
      a <- sapply(x, cumsum)
      row.names(a) <- c('a', 'b', 'c', 'd')
      

      x1 x2
      a 3 2
      b 6 3
      c 9 7
      d 12 12


  • tapply():tapply(X, INDEX, FUN=NULL, ..., simplify=TRUE)
    x <- y <- 1:10
    # 設置分組索引t
    t <- round(runif(10,1,100)%%2)
    tapply(x, t, sum)
    
    # 對於 t=0 時,x=8 再加上 y=55,最後計算結果為 63
    tapply(x, t, sum, y)
    

    0 1 2
    15 30 10

    0 1 2
    70 85 65


  • rapply():rapply(object, f, classes="ANY", deflt=NULL, how=c("unlist", "replace", "list"), ...)
    x <- list(a=12, b=1:4, c=c('b','a'))
    y <- pi
    z <- data.frame(a=rnorm(10), b=1:10)
    a <- list(x=x, y=y, z=z)
    # 對一個 list 的數據進行過濾,把所有數字型進行排序
    rapply(a, sort, classes='numeric', how='replace')
    
    # 把所有字串型加上'++++'
    rapply(a, function(x) paste0(x,'++++'), classes='character', deflt=NA, how='list')
    

    $x
    $x$a [1] 12
    $x$b [1] 1 2 3 4
    $x$c [1] "b" "a"
    $y
    [1] 3.141593
    $z
    a b
    1 -2.21469989 1
    2 -0.62124058 2
    3 -0.04493361 3
    4 -0.01619026 4
    5 0.38984324 5
    6 0.59390132 6
    7 0.82122120 7
    8 0.94383621 8
    9 1.12493092 9
    10 1.51178117 10

    $x
    $x$a [1] NA
    $x$b [1] NA
    $x$c [1] "b++++" "a++++"
    $y [1] NA
    $z
    $z$a [1] NA
    $z$b [1] NA


  • eapply():eapply(env, FUN, ..., all.names=FALSE, USE.NAMES=TRUE)
    env <- new.env()
    env$a <- 1:10
    env$beta <- exp(-3:3)
    env$logic <- c(TRUE, FALSE, FALSE, TRUE)
    env
    ls(env)
    ls.str(env)
    # 計算 env 環境空間中所有變量的均值
    eapply(env, mean)
    
    # 查看所有變數的占用內存大小
    eapply(environment(), object.size)
    

    [1] "a" "beta" "logic"

    a : int [1:10] 1 2 3 4 5 6 7 8 9 10
    beta : num [1:7] 0.0498 0.1353 0.3679 1 2.7183 ...
    logic : logi [1:4] TRUE FALSE FALSE TRUE
    $a [1] 5.5
    $logic [1] 0.5
    $beta [1] 4.535125

    $t 176 bytes
    $mean.1 56 bytes
    $mice.data 71480 bytes
    $x 736 bytes
    $y 56 bytes
    $z 1024 bytes
    $env 56 bytes
    $a 2256 bytes
    $EX1 248 bytes
    $mice_plot 11928 bytes
    $na.rows 648 bytes
    $iris 7256 bytes
    $mean.data 7256 bytes
    $myFUN 13672 bytes
    $data 416 bytes
    $imputeData 7256 bytes
    $data2 912 bytes


圖示

apply家族

比較

  • 從 CPU 的耗時來看,用 for 的計算最耗時,apply 耗時很短,而直接使用内置的向量計算的操作幾乎不耗時。通過上面的測試,優先考虑内置的向量計算,必须要用到循環計算時則使用 apply,應該盡量避免使用 for, while 等操作方法。
    # 封裝fun1
    fun1 <- function(x){
                         myFUN <- function(x, c1, c2){
                                                       c(sum(x[c1],1), mean(x[c2])) 
                                                     }
                         apply(x,1,myFUN,c1='x1',c2=c('x1','x2'))
                       }
    
    # 封裝fun2
    fun2 <- function(x){
                         df<-data.frame()
                         for(i in 1:nrow(x)){
                                              row<-x[i,]
                                              df<-rbind(df,rbind(c(sum(row[1],1), mean(row))))
                                            }
                       }
    
    # 封裝fun3
    fun3 <- function(x){
                         data.frame(x1=x[,1]+1,x2=rowMeans(x))
                       }
    
    # 生成數據集
    x <- cbind(x1=3, x2=c(400:1, 2:500))
    
    # 分別統計 CPU 耗時
    system.time(fun1(x))
    
    system.time(fun2(x))
    
    system.time(fun3(x))
    

    user system elapsed
    0.02 0.00 0.01

    user system elapsed
    0.16 0.00 0.16

    user system elapsed
    0 0 0


  • 如果 simplify=FALSE 和 USE.NAMES=FALSE,sapply 完全等於 lapply
    x <- cbind(x1=3, x2=c(2:1,4:5))
    lapply(data.frame(x), sum)
    sapply(data.frame(x), sum, simplify=FALSE, USE.NAMES=FALSE)
    

    $x1 [1] 12
    $x2 [1] 12


R Basics:資料合併與分割

  • cbind:根據列進行合併,即曡加所有列,m 列的矩陣與 n 列的矩陣列 cbind() 最後變成 m+n 列,合併前提:cbind(a, c)中矩陣 a、c 的行數必須相符

  • rbind:根據列進行合併,即曡加所有行,m 行的矩陣與 n 行的矩陣 rbind() 最後變成 m+n 行,合併前提:rbind(a, c)中矩陣 a、c 的列數必須相符

    x <- c(1, 2, 3)
    y <- c(10, 20, 30)
    union(x ,y) # union 如英文名稱就是取聯集
    

    [1] 1 2 3 10 20 30

    rbind(x, y) # 透過 row 合併
    

    [,1] [,2] [,3]
    x 1 2 3
    y 10 20 30

    cbind(x, y) # 透過 column 合併
    
    x  y   <br>
    

    [1,] 1 10
    [2,] 2 20
    [3,] 3 30

    x <- cbind(c("Tom", "Joe", "Vicky", "Bob"), c(27, 29, 28, 25))
    y <- cbind(c("Tom", "Joe", "Vicky", "Bruce"), c(178, 186, 168, 170))
    colnames(x) <- c("name", "age")
    colnames(y) <- c("name", "tall")
    merge(x, y, by = "name") # 將 data.frame 透過一個欄位進行合併
    

    name age tall
    1 Joe 29 186
    2 Tom 27 178
    3 Vicky 28 168

    merge(x, y, by = "name", all = T) # alt 是用來詢問是否顯示所有資料,像 Bob 與 Bruce 都有一欄資料沒有,所以沒下 all = T,應該不會出現 Bob 與 Bruce 資料
    

    name age tall
    1 Bob 25
    2 Joe 29 186
    3 Tom 27 178
    4 Vicky 28 168
    5 Bruce 170

    merge(x, y, by = "name", all.x = T) # 只顯示 x 有的資料,所以 Bruce 就不會出現
    

    name age tall
    1 Bob 25
    2 Joe 29 186
    3 Tom 27 178
    4 Vicky 28 168

    merge(x, y, by = "name", all.y = T) # 只顯示 y 有的資料,所以 Bob 就不會出現
    

    name age tall
    1 Joe 29 186
    2 Tom 27 178
    3 Vicky 28 168
    4 Bruce 170

    a <- matrix(1:12, 3, 4)
    b <- matrix(-1:-12, 3, 4)
    cbind(a,b)
    

    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
    [1,] 1 4 7 10 -1 -4 -7 -10
    [2,] 2 5 8 11 -2 -5 -8 -11
    [3,] 3 6 9 12 -3 -6 -9 -12

    rbind(a,b)
    

    [,1] [,2] [,3] [,4]
    [1,] 1 4 7 10
    [2,] 2 5 8 11
    [3,] 3 6 9 12
    [4,] -1 -4 -7 -10
    [5,] -2 -5 -8 -11
    [6,] -3 -6 -9 -12

    c <- matrix(-1:-20, 5, 4)
    cbind(a,c)
    

    Error in cbind(a, c) : number of rows of matrices must match (see arg 2)

    rbind(a,c)
    

    [,1] [,2] [,3] [,4]
    [1,] 1 4 7 10
    [2,] 2 5 8 11
    [3,] 3 6 9 12
    [4,] -1 -6 -11 -16
    [5,] -2 -7 -12 -17
    [6,] -3 -8 -13 -18
    [7,] -4 -9 -14 -19
    [8,] -5 -10 -15 -20

參考資訊

Releases

No releases published

Packages

 
 
 

Languages