您的位置:首页 > 移动开发

R_Split-Apply-combine

2015-09-01 17:05 155 查看
昨天看到豆瓣上一篇文章,是作者关于读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是分组因子,返回值是一个列表。

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 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 ...


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

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


Example3:对数据框分组

a <- data.frame(a = 1:10, b = 11:20, c = rep(1:2, each = 5))  #产生一个三列的数据框
a


a  b c
1   1 11 1
2   2 12 1
3   3 13 1
4   4 14 1
5   5 15 1
6   6 16 2
7   7 17 2
8   8 18 2
9   9 19 2
10 10 20 2


b <- split(a, a$c)  #按照第三列分组
b


$`1`
a  b c
1 1 11 1
2 2 12 1
3 3 13 1
4 4 14 1
5 5 15 1

$`2`
a  b c
6   6 16 2
7   7 17 2
8   8 18 2
9   9 19 2
10 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 Temp
29    45   81
35    NA   84
36    NA   85
38    29   82
39    NA   87
40    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 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. = 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包函数的命名规则arraydata.framelistnothing
arrayaaplyadplyalplya_ply
data.framedaplyddplydlplyd_ply
listlaplyldplyllplyl_ply
n replicatesraplyrdplyrlplyr_ply
function argumentsmaplymdplymlplym_ply
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: