天天看點

R_Split-Apply-combine

昨天看到豆瓣上一篇文章,是作者關于讀Hadley Wickham的文章The Split-Apply-Combine Strategy for Data Analysis的筆記。

文章位址

自己在用R整理資料的時候,為了避免顯示循環,使用apply函數族的時候,常常遇到輸入類型和輸出類型搞混的情況,這篇文章對R base中的 split-apply-combine有一個很好的整理。以及介紹了R社群中資料整理大牛Wickham的一個R包-plyr。

plyr包是Hadley Wickham為解決split – apply – combine問題而寫的一個包,其動機在與提供超越for循環和内置的apply函數族的一個一攬子解決方案。使用plyr包可以針對不同的資料類型,在一個函數内同時完成split – apply – combine三個步驟,以實作最大限度的高效和簡潔。

plyr包特别适合處理大型資料集問題,比如對空間資料的空間位置或時間序列面闆資料的時間點模組化,或者在高維數組中進行資料探索等等。

資料轉換常用的一個模式:split-apply-combine。具體的說就是:将一個大資料分拆成小塊,在每一個小塊内進行操作,合并操作結果。

split

函數split()可以按照分組因子,把向量,矩陣和資料框進行适當的分組。它的傳回值是一個清單,代表分組變量每個水準的觀測。這個清單可以使用sapply(),lappy()進行處理(apply – combine步驟),得到問題的最終結果。

split(x,f)其中x是待分組的向量、矩陣、資料框,f是分組因子,傳回值是一個清單。

  1. Example1:對向量分組
n <- 10
nn <- 100
g <- factor(round(n * runif(n * nn)))  #runif産生均勻分布,預設參數是0-1之間的。
x <- rnorm(n * nn) + sqrt(as.numeric(g))
xg <- split(x, g)
str(xg)
           
List of 
$  : num [:]      ...
$  : num [:]    -  ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$  : num [:]      ...
$ : num [:]      ...
           

可以看出傳回值是一個清單。

  1. Example2:對矩陣分組
a <- matrix(c(:, rep(:, )), ncol = )  #産生一個三列的矩陣
a
           
[,] [,] [,]
 [,]           
 [,]           
 [,]           
 [,]           
 [,]           
 [,]           
 [,]           
 [,]           
 [,]           
[,]          
           
b <- split(a, col(a))  # 案列分組
b
           
$`1`
 []                   

$`2`
 []          

$`3`
 []          
           
c <- split(a[, -], factor(a[, ]))  #按照第三列分組
c
           
$`1`
 []               

$`2`
 []              
           
  1. Example3:對資料框分組
a <- data.frame(a = :, b = :, c = rep(:, each = ))  #産生一個三列的資料框
a
           
a  b c
     
     
     
     
     
     
     
     
     
   
           
b <- split(a, a$c)  #按照第三列分組
b
           
$`1`
  a  b c
   
   
   
   
   

$`2`
    a  b c
     
     
     
     
   
           

unsplit()函數是split()函數的逆函數,可以使分組和好如初。

subset()取子集的一個函數

'data.frame':     obs. of   variables:
 $ Ozone  : int      NA     NA ...
 $ Solar.R: int      NA NA     ...
 $ Wind   : num            ...
 $ Temp   : int            ...
 $ Month  : int            ...
 $ Day    : int            ...
           
Ozone Temp
       
    NA   
    NA   
       
    NA   
       
           

cut()劃分數值變量的取值

strsplit()分割字元變量

apply函數族

aplly函數族主要用來完成apply-combine過程,該函數族的使用經常讓我混亂。

apply :Apply Functions Over Array Margins

by :Apply a Function to a Data Frame Split by Factors

eapply :Apply a Function Over Values in an Environment

lapply :Apply a Function over a List or Vector

mapply :Apply a Function to Multiple List or Vector Arguments

rapply :Recursively Apply a Function to a List

tapply :Apply a Function Over a Ragged Array

除此之外,還有可作為lapply變形的sapply,vapply和 replicate,共計10個函數。

apply()函數作用于數組、矩陣、資料框,對行或者列作用,傳回一個向量、數組或者清單

by函數矩陣或者資料框,作用于按行分組的子集,傳回一個清單或者數組。它是tapply的友好版

lapply作用于清單或者向量使用函數,傳回一個清單

sapply是lapply的使用者友好版,如何合适的話,可以傳回一個向量或者矩陣

vapply類似sapply,可以預先定義傳回值的類型

i39 <- sapply(:, seq)  # list of vectors
sapply(i39, fivenum)
           
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]  1.0  1.0    1  1.0  1.0  1.0    1
## [2,]  1.5  1.5    2  2.0  2.5  2.5    3
## [3,]  2.0  2.5    3  3.5  4.0  4.5    5
## [4,]  2.5  3.5    4  5.0  5.5  6.5    7
## [5,]  3.0  4.0    5  6.0  7.0  8.0    9
           
vapply(i39, fivenum, c(Min. = , `1st Qu.` = , Median = , `3rd Qu.` = , Max. = ))
           
##         [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## Min.     1.0  1.0    1  1.0  1.0  1.0    1
## 1st Qu.  1.5  1.5    2  2.0  2.5  2.5    3
## Median   2.0  2.5    3  3.5  4.0  4.5    5
## 3rd Qu.  2.5  3.5    4  5.0  5.5  6.5    7
## Max.     3.0  4.0    5  6.0  7.0  8.0    9
           

mapply()作用于多重清單或者是向量參數

## [[1]]
## []    
## 
## [[2]]
## []   
## 
## [[3]]
## []  
## 
## [[4]]
## [] 
           
## [[1]]
## [] 
## 
## [[2]]
## []  
## 
## [[3]]
## []   
## 
## [[4]]
## []    
           
## [[1]]
## [] 
## 
## [[2]]
## []  
## 
## [[3]]
## []   
## 
## [[4]]
## []    
           
mapply(function(x, y) seq_len(x) + y,
       c(a =  1, b = 2, c = 3),  # names from first
       c(A = 10, B = 0, C = -10))
           
## $a
## [1] 11
## 
## $b
## [1] 1 2
## 
## $c
## [1] -9 -8 -7
           
word <- function(C, k) paste(rep.int(C, k), collapse = "")
utils::str(mapply(word, LETTERS[:], :, SIMPLIFY = FALSE))
           
## List of 6
##  $ A: chr "AAAAAA"
##  $ B: chr "BBBBB"
##  $ C: chr "CCCC"
##  $ D: chr "DDD"
##  $ E: chr "EE"
##  $ F: chr "F"
           

rapply()遞歸的應用一個函數到清單 (可以認為是作用于清單中的每一個元素?)

X <- list(list(a = pi, b = list(c = :)), d = "a test")
X
           
## [[1]]
## [[1]]$a
## [] 
## 
## [[1]]$b
## [[1]]$b$c
## [] 
## 
## 
## 
## $d
## [] "a test"
           
rapply(X, function(x) x, how = "replace")
           
## [[1]]
## [[1]]$a
## [] 
## 
## [[1]]$b
## [[1]]$b$c
## [] 
## 
## 
## 
## $d
## [] "a test"
           
## [[1]]
## [[1]]$a
## [] 
## 
## [[1]]$b
## [[1]]$b$c
## [] 
## 
## 
## 
## $d
## [] "a test"
           
rapply(X, nchar, classes = "character", deflt = as.integer(NA), how = "list")
           
## [[1]]
## [[1]]$a
## [] NA
## 
## [[1]]$b
## [[1]]$b$c
## [] NA
## 
## 
## 
## $d
## [] 
           
rapply(X, nchar, classes = "character", deflt = as.integer(NA), how = "unlist")
           
##   a b.c   d 
##  NA  NA   6
           
## d 
## 6
           
## [[1]]
## [[1]]$a
## [] 
## 
## [[1]]$b
## [[1]]$b$c
## [] 
## 
## 
## 
## $d
## [] "a test"
           

tapply()對不規則的數組按确定的因子計算函數

##   breaks wool tension
## 1     26    A       L
## 2     30    A       L
## 3     54    A       L
## 4     25    A       L
## 5     70    A       L
## 6     52    A       L
           
tapply(warpbreaks$breaks, warpbreaks[, -], sum)
           
##     tension
## wool   L   M   H
##    A 401 216 221
##    B 254 259 169
           

plyr包

plyr包函數的命名規則 array data.frame list nothing
array aaply adply alply a_ply
data.frame daply ddply dlply d_ply
list laply ldply llply l_ply
n replicates raply rdply rlply r_ply
function arguments maply mdply mlply m_ply