R向量化操作

向量是R的基本运算对象,在通常的数据处理中,向量化计算可以大大提高运算效率。在R中,apply系列函数提供了最主要的向量化运算,这里总结一下apply系列函数的学习记录。

apply() 函数

常用调用

1
apply(X, MARGIN, FUN, ...)
  • apply() 函数主要作用于数组和矩阵,如果X是数据框,apply() 会通过as.matrix()或者as. array()将其转为矩阵。如果所有行列不是数值型或者类型不一致,导致转换失败,那么apply是运算不出任何一列的结果,因此不建议对数据框使用。
  • MARGIN参数为1时,作用对象是行,为2时作用对象是列,c(1, 2)指作用对象为行列。

  • 可以指定函数的参数

使用

在进行行列的合计或者平均等统计量计算时,用apply()是很有效率的。例如:

1
2
3
> apply(state.x77, 2, min)
Population Income Illiteracy Life Exp Murder HS Grad Frost Area
365.00 3098.00 0.50 67.96 1.40 37.80 0.00 1049.00

在对向量进行分组计算是,apply()也是非常容易实现的,例如我们可以把向量临时分为行列,然后对其使用apply()函数。

1
2
3
> x = 1:12
> apply(matrix(x, ncol = 3, byrow = TRUE), 1, sum)
[1] 6 15 24 33

当然,在进行简单的行列统计量计算时,也可以直接使用rowSums(), colSums(), rowSums(), rowMeans(), colMeans()函数。

lapply()sapply()函数

lapply()函数读入一个列表,将函数应用到列表的每一个元素,然后返回一个与原来相同长度的列表。

sapply()函数将lapply()函数的结果做了简单化处理,通常,如果结果是一个列表,其中每个元素的长度都是1,那么sapply()将返回一个向量。如果结果是一个列表,其中每个元素都是相同长度的向量(大于1),那么sapply()将返回一个矩阵。如果sapply()不能解决问题,那么它只返回一个列表,与lapply()会给出的结果没有什么不同。

常用调用

调用方法 lapply()sapply()是相同的。

1
2
lapply(X, FUN, ...)
sapply(X, FUN, ...)

使用

首先对数据使用lapply()函数,查看结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
> state <- as.data.frame(state.x77)
> cls_list <- lapply(state, class)
> cls_list <- lapply(state, class)
> cls_list
$Population
[1] "numeric"
$Income
[1] "numeric"
$Illiteracy
[1] "numeric"
$`Life Exp`
[1] "numeric"
$Murder
[1] "numeric"
$`HS Grad`
[1] "numeric"
$Frost
[1] "numeric"
$Area
[1] "numeric"
> class(cls_list)
[1] "list"
> length(cls_list)
[1] 8

我们可以看到,返回结果是一个长度为8的列表,每个元素对应数据集的一列。如果要简化输出效果,我们可以使用as.character(cls_list),使其转化为一个字符型向量,但是使用sapple()函数可以简单完成这种目的。

1
2
3
4
5
6
> cls_vect <- sapply(state, class)
> cls_vect
Population Income Illiteracy Life Exp Murder HS Grad Frost Area
"numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric"
> class(cls_vect)
[1] "character"

当每个元素都是相同长度的向量(大于1)时,则返回一个矩阵。

1
2
3
4
5
6
7
> cls_mtx <- sapply(state, range)
> cls_mtx
Population Income Illiteracy Life Exp Murder HS Grad Frost Area
[1,] 365 3098 0.5 67.96 1.4 37.8 0 1049
[2,] 21198 6315 2.8 73.60 15.1 67.3 188 566432
> class(cls_mtx)
[1] "matrix"

当返回结果长度不同时,sapply()函数只返回一个列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
> cls_unq <- sapply(state, unique)
> cls_unq
$Population
[1] 3615 365 2212 2110 21198 2541 3100 579 8277 4931 868 813 11197 5313 2861
[16] 2280 3387 3806 1058 4122 5814 9111 3921 2341 4767 746 1544 590 812 7333
[31] 1144 18076 5441 637 10735 2715 2284 11860 931 2816 681 4173 12237 1203 472
[46] 4981 3559 1799 4589 376
$Income
[1] 3624 6315 4530 3378 5114 4884 5348 4809 4815 4091 4963 4119 5107 4458 4628 4669 3712 3545
[19] 3694 5299 4755 4751 4675 3098 4254 4347 4508 5149 4281 5237 3601 4903 3875 5087 4561 3983
[37] 4660 4449 4558 3635 4167 3821 4188 4022 3907 4701 4864 3617 4468 4566
$Illiteracy
[1] 2.1 1.5 1.8 1.9 1.1 0.7 0.9 1.3 2.0 0.6 0.5 1.6 2.8 2.4 0.8 2.2 1.4 1.0 2.3 1.7
$`Life Exp`
[1] 69.05 69.31 70.55 70.66 71.71 72.06 72.48 70.06 68.54 73.60 71.87 70.14 70.88 72.56 72.58
[16] 70.10 68.76 70.39 70.22 71.83 70.63 72.96 68.09 70.69 70.56 72.60 69.03 71.23 70.93 70.32
[31] 69.21 72.78 70.82 71.42 72.13 70.43 71.90 67.96 72.08 70.11 70.90 72.90 71.64 70.08 71.72
[46] 69.48 70.29
$Murder
[1] 15.1 11.3 7.8 10.1 10.3 6.8 3.1 6.2 10.7 13.9 5.3 7.1 2.3 4.5 10.6 13.2 2.7 8.5
[19] 3.3 11.1 12.5 9.3 5.0 2.9 11.5 5.2 9.7 10.9 1.4 7.4 6.4 4.2 6.1 2.4 11.6 1.7
[37] 11.0 12.2 5.5 9.5 4.3 6.7 3.0 6.9
$`HS Grad`
[1] 41.3 66.7 58.1 39.9 62.6 63.9 56.0 54.6 52.6 40.6 61.9 59.5 52.9 59.0 59.9 38.5 42.2 54.7
[19] 52.3 58.5 52.8 57.6 41.0 48.8 59.2 59.3 65.2 52.5 55.2 52.7 50.3 53.2 51.6 60.0 50.2 46.4
[37] 37.8 53.3 41.8 47.4 67.3 57.1 47.8 63.5 41.6 54.5 62.9
$Frost
[1] 20 152 15 65 166 139 103 11 60 0 126 127 122 140 114 95 12 161 101 125 160 50 108
[24] 155 188 174 115 120 82 80 186 124 44 172 70 35 137 168 85 32 100 149 173
$Area
[1] 50708 566432 113417 51945 156361 103766 4862 1982 54090 58073 6425 82677 55748
[14] 36097 55941 81787 39650 44930 30920 9891 7826 56817 79289 47296 68995 145587
[27] 76483 109889 9027 7521 121412 47831 48798 69273 40975 68782 96184 44966 1049
[40] 30225 75955 41328 262134 82096 9267 39780 66570 24070 54464 97203
> class(cls_unq)
[1] "list"

我们再对数据集使用lapply()函数,通过调用identical()可以看出,当返回结果长度不同时sapply()函数与lapply()函数返回结果相同。

1
2
3
4
> cls_unq_l <- lapply(state, unique)
> identical(cls_unq, cls_unq_l)
[1] TRUE

vapply()tapply()函数

vapply类似于sapply,但是有一个预先指定的返回值类型,因此它可以更安全,针对大量数据集时也可能更快。tapply()函数可以实现对一些变量分组应用指定函数。

常用调用

1
2
vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
tapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)

使用

先看sapply()的最后一个例子,返回结果长度不同时会以列表形式呈现。当我们使用vapply()预先指定返回类型时,就会提示错误信息。

1
2
3
> vapply(state, unique, numeric(1))
Error in vapply(state, unique, numeric(1)) : 值的长度必需为1
但FUN(X[[1]])结果的长度却是50

但是大部分情况下sapply()都能够有很好的表现,还能减少输入量。

其次是tapply(),这里调用airquality数据集来计算按月分组的平均风速

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> table(airquality$Month)
5 6 7 8 9
31 30 31 31 30
> table(airquality$Wind)
1.7 2.3 2.8 3.4 4 4.1 4.6 5.1 5.7 6.3 6.9 7.4 8 8.6 9.2 9.7 10.3 10.9 11.5 12 12.6
1 1 1 1 1 1 4 3 3 8 9 10 11 8 8 11 11 8 15 4 3
13.2 13.8 14.3 14.9 15.5 16.1 16.6 18.4 20.1 20.7
2 5 6 8 3 1 3 1 1 1
> tapply(airquality$Wind, airquality$Month, mean)
5 6 7 8 9
11.622581 10.266667 8.941935 8.793548 10.180000

mapply()函数

函数mapply()是函数sapply()的变形版,mapply() 将函数FUN依次应用每一个参数的第一个元素、第二个元素、第三个元素上。

常用调用

1
mapply(FUN, ...

使用

再返回结果长度相同时,sapply()mapply()结果是一样的,例如我们对airquality数据前三列求均值。

1
2
3
4
5
6
7
> mapply(mean, airquality[,1:3], na.rm = T)
Ozone Solar.R Wind
42.129310 185.931507 9.957516
> sapply(airquality[,1:3], mean, na.rm = T)
Ozone Solar.R Wind
42.129310 185.931507 9.957516

但是在返回结果长度不同时,sapply()就会返回错误提示。

1
2
> sapply(1:4, rep, 1:4)
Error in FUN(X[[i]], ...) : 'times'参数不对

我们把rep参数设置为2时,会返回一个矩阵。

1
2
3
4
5
6
7
8
> temp <- sapply(1:4, rep, 2)
> temp
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 1 2 3 4
> class(temp)
[1] "matrix"

但是mapply()函数可以把rep依次应用到每个参数的每个元素。

1
2
3
4
5
6
7
8
9
10
11
12
> 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

参考

  1. R Programming
  2. R语言apply家族:apply, lapply,sapply,vapply,mapply的用法
  3. R中利用apply、tapply、lapply、sapply、mapply、table等函数进行分组统计
  4. R语言中apply,sapply,tapply函数的区别与应用