R函数式编程
Functional Programming in R
R语言的循环很慢,同时语法有很复杂,陷阱很多。举例来说,逐行遍历一个矩阵有两种写法:
(1)
1 | for (i in seq_len ( nrow (m))){ print (i)} |
(2)
1 | for (i in 1: nrow (m)){ print (i)} |
这两个写法那个对?或者两个都对?
熟悉R的用户自然会用(1),因为当m矩阵的行数为零时,只有(1)的结果是正确的:
1 2 3 4 5 | > m <- matrix (, nr = 0, nc = 0) > for (i in seq_len ( nrow (m))){ print (i)} > for (i in 1: nrow (m)){ print (i)} [1] 1 [1] 0 |
为了避免手动写循环,一种折中的解决方案是用Filter, Reduce, Map等函数式编程的概念。
这些函数可以比较自然的处理列表(list)或者向量(vector)类型。举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | l <- as.list ( seq (9, 1, -1)) d <- data.frame (a = c (1, 2), b = c (3, 4)) m <- matrix ( seq (9, 1, -1), 3, 3) v <- seq (9, 1, -1) isEven <- function (x) { x %% 2 == 0 } isEven (1:3) Filter (isEven, l) ## Filter(isEven, d) ## this does not work Filter (isEven, m) Filter (isEven, v) Position (isEven, l) # Position(isEven, d) ## this does not work Position (isEven, m) Position (isEven, v) Find (isEven, l) # Find(isEven, d) ## this does not work Find (isEven, m) Find (isEven, v) |
可以看到,对于列表(list)或者向量(vector)类型,R内建的函数式函数(更多的见[1])还是很方便的。
如果想把函数式编程玩出更多花样,可以看看Hadley的新书Adv-R(参见[2])。
这里还有个问题,这种函数式的写法速度如何?下面的代码告诉我们函数式编程节省了写程序的时间,在某些情况下也许也能节省计算时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | library (microbenchmark) v <- seq (10000) m1 <- function (v) { v[v%%2 == 0] } m2 <- function (v) { res <- vector () for (i in v) { if (i %% 2 == 0) { res <- c (res, i) } } res } m3 <- function (v) { Filter (isEven, v) } microbenchmark (res1 <- m1 (v), res2 <- m2 (v), res3 <- m3 (v), times = 1000) |
下面是结果:
1 2 3 4 5 | Unit: microseconds expr min lq mean median uq max neval res1 <- m1(v) 341.038 348.526 529.9475 356.225 380.6965 58359.46 1000 res2 <- m2(v) 33687.987 38433.148 48014.3656 39791.000 41751.3955 303604.96 1000 res3 <- m3(v) 6178.547 6648.369 8493.9365 6999.976 7445.0725 124781.90 1000 |
在上面的例子中,
第一种是向量化的赋值,速度最快。
第二种是用循环,速度最慢,
第三种是函数式,速度居中。
不过据我的经验,当v的维数很小时(比如只有100个数),函数式相对于循坏的优势越来越小,甚至比循环要慢。
题外话:据说R的核心是类似于Scheme,也是一种函数式语言。但是在速度上对函数式编程的支持看来还有很大的提升空间。
[1]https://stat.ethz.ch/R-manual/R-devel/library/base/html/funprog.html
[2]Advanced R http://adv-r.had.co.nz/Functional-programming.html