天天看点

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