并行 apply 系列

R 并行编程

Nabeel Imam

Data Science

孕期体重增益

print(ls_weights)
$AK
  [1] 30 33 50 30 26 99 52 28 24 40 30 99 40
 [14] 20 20 39 25 30 20 33 99 54 30 99 30 38
...
$AL
   [1] 60 32 30 21 30 27 28 32 18 28 30 24 59
  [14] 30 19 30 15 17 18 53 26  5 25 41 50 20
...
$AR
  [1] 31 40 30 99 27 36 30 35 25 19 10 25 40
 [14] 33 37 12 34 99 43 26 28 99 37 30 26  6
...
1 源自 CDC 出生数据(Natality Data)
R 并行编程

用 mclapply 进行 FORK

boot_mean <- function (weights) {

  est <- rep(0, 1e4)

  for (i in 1:1e4) {
    b <- sample(weights, replace = T)
    est[i] <- mean(b)
  }

  return(est)
}

ls_boot <- mclapply(ls_weights, boot_mean,

mc.cores = 4)
  • 提速 20–40%
  • 后台生成 FORK 集群
    • 无需手动创建集群
    • 不支持 Windows
R 并行编程

用 parLapplyLB 平衡负载

两位职员任务繁重,另一位空闲。

lapply(ls_weights, length)
   AK    AL    AR    AZ    CA    CO    CT   DC    DE    FL    GA    HI    IA  ...
  260  1503   816  1649 14869  1286  1151  520   295  4693  2824   510   891  ...
1 由 Freepik 设计
R 并行编程

用 parLapplyLB 平衡负载

microbenchmark(
  "parLapply" = {
    cl <- makeCluster(4)
    ls <- parLapply(cl, ls_weights, boot_mean)
    stopCluster(cl)
  },
  "parLapplyLB" = {
    cl <- makeCluster(4)
    ls <- parLapplyLB(cl, ls_weights, boot_mean)
    stopCluster(cl)
  },
  times = 10
)
Unit: seconds
       expr      min     mean      max neval
  parLapply 15.77250 16.38548 16.83822    10
parLapplyLB 14.55609 15.49170 17.26866    10
  • 平均执行时间从 16.4 秒降至 15.5 秒(约 5% 降幅)
R 并行编程

循环多个参数

add <- function (x, y, z) x + y + z


value1 <- c(0.5, 3.2, 5.1, 1.9) value2 <- c(0.1, 0.5, 0.2, 2.4) value3 <- 5

首次迭代将 value1、value2 和 value3 的第一个元素相加。第二次迭代相加各向量的第二个元素,依此类推。

R 并行编程

clusterMap

cl <- makeCluster(4)


clusterMap(cl, add,
x = value1, y = value2, z = value3) # 单个值 stopCluster(cl)
print(value3)
[1] 5
[[1]]
[1] 5.6

[[2]]
[1] 8.5

[[3]]
[1] 10.2

[[4]]
[1] 8.4
R 并行编程

clusterMap 与 parLapply

clusterMap(cl,         # 集群
           add,        # 函数
           x = value1, # 多个输入
           y = value2,
           z = value3) # 可为单值复用
parLapply(cl,                # 集群
          input,             # 单个输入
          fun,               # 函数
          arg_name = static) # 导出的静态变量
                             # 传给具名参数
R 并行编程

用 clusterMap 估计增重分布

print(ls_weights)
$AK
  [1] 30 33 50 30 26 99 52 28 24 40 30 99 40
...
print(ls_plur)
$AK
  [1] 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1
  ...
boot_dist <- function (weights, pluralities) {
  est <- rep(0, 1e4)
  ratio <- weights/pluralities
  for (i in 1:1e4) {
    b <- sample(ratio, replace = T)
    est[i] <- mean(b)
  }
  return(est)
}


cl <- makeCluster(4)
result <- clusterMap(cl, boot_dist,
weights = ls_weights, pluralities = ls_plur) stopCluster(cl)
R 并行编程

出生总数

print(mat_births)
     1   2   3   4   5   6   7   8   9  10  11  12
AK   7  13   8   8   5   9  12  19  16  16   7  16
AL  55  58  79  66  48  63  69  81  74  76  61  82
AR  28  28  41  37  40  40  42  52  40  44  33  38
AZ  69  70  70  71  68  61  73  81  76  74  87  62
CA 603 599 659 601 669 719 675 687 660 698 703 633
CO  50  55  72  56  63  56  56  70  58  48  53  58
CT  51  51  57  58  59  41  51  46  54  56  58  52
DC  25  18  14  40  22  19  24  25  20  26  20  25
...
R 并行编程

并行进行行/列运算

cl <- makeCluster(4)

# 列操作用 parCapply parCapply(cl, mat_births, sum)
# 行操作用 parRapply parRapply(cl, mat_births, sum) stopCluster(cl)
  • 列求和

     1    2    3    4    5    6    7
    4258 3966 4437 4345 4371 4482 4614
     8    9   10   11   12
    4738 4686 4483 4427 4247
    
  • 行求和

    AK   AL   AR   AZ   CA   CO   CT
    136  812  463  862 7906  695  634
    DC   DE   FL   GA   HI   IA   ID
    278  151 2519 1512  254  472  237
    ...
    
R 并行编程

Vamos praticar!

R 并行编程

Preparing Video For Download...