R_Split-Apply-combine

来源:互联网 发布:麦当劳 金拱门 知乎 编辑:程序博客网 时间:2024/05/18 01:34

昨天看到豆瓣上一篇文章,是作者关于读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 <- 10nn <- 100g <- 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 11$ 0 : num [1:50] 1.858 1.999 0.503 2.771 1.624 ...$ 1 : num [1:108] 1.836 1.428 1.432 -0.332 2.857 ...$ 2 : num [1:100] 0.162 2.657 0.151 0.212 1.906 ...$ 3 : num [1:103] 1.16 1.78 3.24 1.9 1.18 ...$ 4 : num [1:104] 3.46 2.58 2.5 3.36 1.97 ...$ 5 : num [1:87] 2.99 2.21 3.39 2.47 2.37 ...$ 6 : num [1:107] 2.88 1.79 1.85 4.14 3.48 ...$ 7 : num [1:82] 4.32 3.34 2.62 2.01 4.02 ...$ 8 : num [1:93] 1.67 5.11 2.8 1.83 2.52 ...$ 9 : num [1:123] 3.6 4.72 2.08 2.32 1.78 ...$ 10: num [1:43] 4.14 1.29 4.14 3.29 3.55 ...

可以看出返回值是一个列表。

  1. Example2:对矩阵分组
a <- matrix(c(1:20, rep(1:2, 5)), ncol = 3)  #产生一个三列的矩阵a
      [,1] [,2] [,3] [1,]    1   11    1 [2,]    2   12    2 [3,]    3   13    1 [4,]    4   14    2 [5,]    5   15    1 [6,]    6   16    2 [7,]    7   17    1 [8,]    8   18    2 [9,]    9   19    1[10,]   10   20    2
b <- split(a, col(a))  # 案列分组b
$`1` [1]  1  2  3  4  5  6  7  8  9 10$`2` [1] 11 12 13 14 15 16 17 18 19 20$`3` [1] 1 2 1 2 1 2 1 2 1 2
c <- split(a[, -3], factor(a[, 3]))  #按照第三列分组c
$`1` [1]  1  3  5  7  9 11 13 15 17 19$`2` [1]  2  4  6  8 10 12 14 16 18 20
  1. Example3:对数据框分组
a <- data.frame(a = 1:10, b = 11:20, c = rep(1:2, each = 5))  #产生一个三列的数据框a
    a  b c1   1 11 12   2 12 13   3 13 14   4 14 15   5 15 16   6 16 27   7 17 28   8 18 29   9 19 210 10 20 2
b <- split(a, a$c)  #按照第三列分组b
$`1`  a  b c1 1 11 12 2 12 13 3 13 14 4 14 15 5 15 1$`2`    a  b c6   6 16 27   7 17 28   8 18 29   9 19 210 10 20 2

unsplit()函数是split()函数的逆函数,可以使分组和好如初。
subset()取子集的一个函数

str(airquality)
'data.frame':    153 obs. of  6 variables: $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ... $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ... $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ... $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ... $ Month  : int  5 5 5 5 5 5 5 5 5 5 ... $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...
head(subset(airquality, Temp > 80, select = c(Ozone, Temp)))
   Ozone Temp29    45   8135    NA   8436    NA   8538    29   8239    NA   8740    71   90

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(3:9, seq)  # list of vectorssapply(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. = 0, `1st Qu.` = 0, Median = 0, `3rd Qu.` = 0, Max. = 0))
##         [,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()作用于多重列表或者是向量参数

mapply(rep, 1:4, 4:1)
## [[1]]## [1] 1 1 1 1## ## [[2]]## [1] 2 2 2## ## [[3]]## [1] 3 3## ## [[4]]## [1] 4
mapply(rep, times = 1:4, x = 4:1)
## [[1]]## [1] 4## ## [[2]]## [1] 3 3## ## [[3]]## [1] 2 2 2## ## [[4]]## [1] 1 1 1 1
mapply(rep, times = 1:4, MoreArgs = list(x = 42))
## [[1]]## [1] 42## ## [[2]]## [1] 42 42## ## [[3]]## [1] 42 42 42## ## [[4]]## [1] 42 42 42 42
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[1:6], 6:1, 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 = 1:1)), d = "a test")X
## [[1]]## [[1]]$a## [1] 3.142## ## [[1]]$b## [[1]]$b$c## [1] 1## ## ## ## $d## [1] "a test"
rapply(X, function(x) x, how = "replace")
## [[1]]## [[1]]$a## [1] 3.142## ## [[1]]$b## [[1]]$b$c## [1] 1## ## ## ## $d## [1] "a test"
rapply(X, sqrt, classes = "numeric", how = "replace")
## [[1]]## [[1]]$a## [1] 1.772## ## [[1]]$b## [[1]]$b$c## [1] 1## ## ## ## $d## [1] "a test"
rapply(X, nchar, classes = "character", deflt = as.integer(NA), how = "list")
## [[1]]## [[1]]$a## [1] NA## ## [[1]]$b## [[1]]$b$c## [1] NA## ## ## ## $d## [1] 6
rapply(X, nchar, classes = "character", deflt = as.integer(NA), how = "unlist")
##   a b.c   d ##  NA  NA   6
rapply(X, nchar, classes = "character", how = "unlist")
## d ## 6
rapply(X, log, classes = "numeric", how = "replace", base = 2)
## [[1]]## [[1]]$a## [1] 1.651## ## [[1]]$b## [[1]]$b$c## [1] 1## ## ## ## $d## [1] "a test"

tapply()对不规则的数组按确定的因子计算函数

head(warpbreaks)
##   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[, -1], 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
0 0
原创粉丝点击