Skip to main content
 首页 » 编程设计

R语言并行计算实战教程

2022年07月19日127zhwl

foreach包增强了R循环遍历功能,并且提供了并行执行能力。本文通过示例带你轻松掌握这个高级技能。

foreach语法介绍

%do% 和 %dopar% 是对遍历对象执行一段业务功能代码的操作。

# 串行执行使用 --> %do% 
output <- foreach(i = 'some object to iterate over', 'options') %do% {ex} 
 
# 并行执行使用 --> %dopar% 
output <- foreach(i = 'some object to iterate over', 'options') %dopar% {ex} 

其中ex是表达式,在foreach循环环境中会被运行多次,%do%串行执行,%dopar%并行执行。
执行ex的结果默认作为list类型返回,我们通过.combine参数指定返回结果类型。c用于连接执行结果为向量类型,‘cbind’ 和 ‘rbind’ 合并向量为矩阵类型,‘+’ 和 ‘*’ 用于处理数值类型。

简单示例

# 求平方 
# 等效于 square <- function(x) x^2; lapply(1:3, square) 
foreach(i=1:3) %do% 
  i^2 
 
##多个参数 
 
foreach(i=1:4, j=7:10) %do% 
	sqrt(i*j) 
 
 
# 等效于 colMeans(m) 
# 生成3*3矩阵 
m <- matrix(rnorm(9), 3, 3) 
# c 生成向量 
foreach(i=1:ncol(m), .combine=c) %do% 
  mean(m[,i]) 
# 结果 
# [1]  0.5745559 -0.1177918  1.4583174 
 
 

并行执行

在执行并行计算之前,需要声明集群,即告诉R我们有多个核(cpu)。具体步骤如下:

  1. 加载包doParallel,增强foreach函数的功能
  2. 检测机器CPU核数,一般规则是至少保留一核执行其他任务。假设你是8核,则最多设置为7
  3. 声明集群,使用makeCluster(coreNum, type).

其中type可以为PSOCK、FORK,前者创建新的session,后者拷贝当前session;

  1. 使用registerDoParallel函数注册集群。
library(doParallel) 
detectCores() 
# 8 
 
myCluster <- makeCluster(7, # number of cores to use 
                         type = "FORK") # type of cluster 
# 注册计算 
registerDoParallel(myCluster) 
 
data <- foreach(item = 1:10, .combine = 'c') %dopar% { 
  item = item *2 
} 
 
data 

综合示例实战

最后我们通过实际例子展示如何高效使用foreach函数。
某业务每天的记录保留在当天日期(yyyy-MM-dd)为文件夹的data.csv文件中,现在我们编写函数一次性读取一段时间内的所有记录并合并结果为数据框。

假设文件夹为sales,则其中内容为:
2022-01-01/data.csv
2022-01-02/data.csv

2022-06-09/data.csv

代码如下:

library(plyr) 
library(foreach) 
 
readCsvDates <- function(base.dir, date.from, date.to) { 
  # 字符串转为日期 
  date.from <- as.Date(date.from) 
  date.to <- as.Date(date.to) 
  # 生成日期序列 
  dates <- seq.Date(date.from, date.to, by = "day") 
   
  # 利用foreach读取文件,ldply组合结果为数据框 
  x <- ldply(foreach(day = dates, combine = rbind) %do% { 
    read.csv(sprintf("%s/%s/data.csv", base.dir, day), 
             header = T, 
             sep = "\t", stringsAsFactors = F) 
  }) 
  x 
} 
 
## 定义readData函数 
readSales <- function(date.from, date.to) { 
  data <- readCsvDates("sales", date.from, date.to) 
  data 
} 
 
# 执行文件加载,生成数据框 
result <- readSales("2022-05-01", "2022-05-02") 
head(result) 

本文参考链接:https://blog.csdn.net/neweastsun/article/details/125211464
阅读延展