一、背景
当今社会,数据量剧增让我们越来越关注计算或算法的效率。“并行和分布式”计算是目前主流的能有效提升计算效率的方法,但学习及实施成本较高。所以,向量化运算对于提升计算效率是个不错的选择。作为并行计算的先驱,向量化运算在提升计算效率的同时,也能一定程度上培养数据分析人员的结构化思维。
向量化计算是一种特殊的并行计算的方式,相比于一般程序在同一时间只执行一个操作的方式,它可以在同一时间执行多次操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量(from wikipedia);在R中,向量是R的基本运算对象,当你对一个向量计算时,R会对每个元素进行分别处理,最终结果以向量的形式输出,向量化运算在R中有很广泛的应用场景。
二、应用场景
应用场景很大程度上决定我们知识的储备和工具的选择,总结了一下,向量化运算在R中的应用场景主要有以下三点:
向量的取值与赋值
apply系列函数在数据处理中的应用
矩阵运算
向量的取值与赋值:这部分应用范围较广,针对较大的数据,如果把向量化运算的思维融入抽样当中,也能明显提升抽样效率,向量的赋值最常见的应用是做缺失值的填补,以上两个应用时数据挖掘的基本功,好的模型需要高质量的数据,高质量的数据需要花精力去清洗。
向量化运算最熟悉的莫过于apply系列函数,这部分函数主要包括:apply,lapply,sapply,tapply,aggreate,by,这几个函数比较基础的向量化运算函数。当然也有Hadley Wickham两个包plyr和reshape,能很容易实现以上函数的功能。 矩阵运算的重要程度相比都很清楚,R也一直提倡做矩阵运算,特别是在文本挖掘和图形处理中的稀疏矩阵处理,向量化运算能大幅提升运算的效率;
三、实例介绍
这个部分主要简单介绍一下前面说过的几个向量化运算函数,然后了解一下plyr包(通过Rstudio镜像获取的下载R包数据发现这个包的下载量一直是第一);
1.apply:对矩阵/数组的行或列应用函数
#生成4*4的矩阵
M <- matrix(seq(1,16), 4, 4)
#对行求和
apply(M, 1, sum)
[1] 120 128 136 144
#分别对行和列汇总
apply(M, c(1,2), sum)
[,1] [,2] [,3] [,4]
[1,] 18 26 34 42
[2,] 20 28 36 44
[3,] 22 30 38 46
[4,] 24 32 40 48
#注:对于矩阵还可以用colMeans, rowMeans, colSums, rowSums做行列运算
2.lapply:对列表应用函数,返回列表
x <- list(a = 1, b = 1:3, c = 10:100)
lapply(x, FUN = sum)
$a
[1] 1
$b
[1] 6
$c
[1] 5005
3.sapply:对列表应用函数,返回向量,这个比较常用,等价于unlist(lapply(…)),用lapply计算,然后把结果变为向量;
x <- list(a = 1, b = 1:3, c = 10:100)
sapply(x, FUN = sum)
a b c
1 6 5005
unlist(lapply(x,sum))
a b c
1 6 5005
4.tapply:对各因子应用函数(也就是分组计算),这个也常用;
x <- 1:20
y <- factor(rep(letters[1:5], each = 4))
tapply(x, y, sum)
a b c d e
10 26 42 58 74
5.aggreate:split-apply-combine,拆分成子集,分别计算合并结果输出;
testDF <- data.frame(v1 = c(1,3,5,7,8,3,5,NA,4,5,7,9),
v2 = c(11,33,55,77,88,33,55,NA,44,55,77,99) )
by1 <- c("red", "blue", 1, 2, NA, "big", 1, 2, "red", 1, NA, 12)
by2 <- c("wet", "dry", 99, 95, NA, "damp", 95, 99, "red", 99, NA, NA)
aggregate(x = testDF, by = list(by1, by2), FUN = "mean")
Group.1 Group.2 v1 v2
1 1 95 5 55
2 2 95 7 77
3 1 99 5 55
4 2 99 NA NA
5 big damp 3 33
6 blue dry 3 33
7 red red 4 44
8 red wet 1 11
更简洁易用的plyr包
以上几个函数在实际应用中比较容易混淆,针对输入对象与输出对象应该应用什么函数,见下图:
1
坦白说,以上函数不太容易记住,再来看一下plyr的函数,取输入输出对象的第一个字母+ply;通俗易懂;
2
以常用的ddply函数为例做演示:
#以mtcars数据为例
str(mtcars)
'data.frame': 32 obs. of 11 variables:
$ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
$ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
$ disp: num 160 160 108 258 360 ...
$ hp : num 110 110 93 110 175 105 245 62 95 123 ...
$ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
$ wt : num 2.62 2.88 2.32 3.21 3.44 ...
$ qsec: num 16.5 17 18.6 19.4 17 ...
$ vs : num 0 0 1 1 0 1 0 1 1 1 ...
$ am : num 1 1 1 0 0 0 0 0 0 0 ...
$ gear: num 4 4 4 3 3 3 3 4 4 4 ...
$ carb: num 4 4 1 1 2 1 4 2 2 4 ...
#计算每个气缸水平下,mpg的均值和标准差
ddply(mtcars,"cyl",summarise,mean.mpg=mean(mpg),sd.mpg=sd(mpg))
cyl mean.mpg sd.mpg
1 4 26.66364 4.509828
2 6 19.74286 1.453567
3 8 15.10000 2.560048
注:数据量比较大时,plyr包的运算效率不理想,曾经用ddply处理一个347万*9的数据框,半个小时没出结果,后来我就放弃了;
plyr上手比较快,结合reshape,掌握部分函数,基本就可以远离EXCEL透视表了,想接着往下走也很容易。
来源:http://www.itongji.cn/article/0H524632013.html |