为 ML 相关的网络抓取加载数千个 URL - 代码非常慢,需要效率提示

Loading thousands of URLS for ML-related web-scraping - code is VERY slow, need efficiency tips

我正在通过从各个网站抓取数据来构建一个数据集,用于股票信号预测算法。我的算法设置方式涉及分层 for 循环和加载数千个 URL,因为每个 link 指的是股票及其各种定量统计数据。需要帮助提高处理速度。有什么建议吗?

我已经和几个不同的人谈过如何解决这个问题,有些人推荐矢量化,但这对我来说是新的。我也试过切换到数据table,但我没有看到太大的变化。 eval 行是我学会了以我想要的方式操作数据的技巧,但我认为这可能是它速度慢的原因,但我对此表示怀疑。我也想知道远程处理,但这可能超出了 R 世界。

对于下面的代码,假设还有 4 个这样的部分用于我要加载的来自不同网站的其他变量,并且所有这些块都在一个更大的 for 循环中,因为我正在生成两个数据集 (设置 = c("training, testing")).

tryCatch 用于防止代码在加载 URL 时遇到错误而停止。这些 url 被加载到一个列表中,每个股票一个 - 所以它们很长。第二个 for 循环从 URLS 抓取数据并将它们以正确的格式发布到数据框中。

library(quantmod)
library(readr)
library(rvest)
library(data.table)

urlsmacd <-  vector("list", length = 
eval(parse(text=as.name(paste0("nrow(", set[y], ")", sep = "")))))
for(h in 1:eval(parse(text=as.name(paste0("nrow(", set[y], ")", sep = 
""))))){
  urlsmacd[h] <- paste0('http://www.stockta.com/cgi-bin/analysis.pl? 
symb=',eval(parse(text=as.name(paste0(set[y],"[,1][h]", sep = 
"")))),'&mode=table&table=macd&num1=1', sep = '')
}

for(j in 1:eval(parse(text=as.name(paste0("nrow(", set[y], ")", sep = 
""))))){
  tryCatch({
html <- read_html(urlsmacd[[j]])

#get macd html
MACD26 <- html_nodes(html,'.borderTd~ .borderTd+ .borderTd:nth-child(3) 
font')
MACD26 <- toString(MACD26)
MACD26 <-  gsub("<[^>]+>", "", MACD26)
if(!is.na(MACD26)){
  MACD26 <- as.double(MACD26)
}
eval(parse(text=as.name(paste0(set[y],"$","MACD26[j] <- MACD26"))))

MACD12 <- html_nodes(html,'.borderTd+ .borderTd:nth-child(2) font')
MACD12 <- toString(MACD12)
MACD12 <-  gsub("<[^>]+>", "",MACD12)
if(!is.na(MACD12)){
  MACD12 <- as.double(MACD12)
}
eval(parse(text=as.name(paste0(set[y],"$","MACD12[j] <- MACD12"))))

  }, error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
    }

综上所述,这个过程大约需要 6 个小时。按照这个速度,减少这个过程的时间将使我的项目进展变得容易得多。

感谢 Whosebug 人员的支持。

检查 doParallel 包。它具有 foreach 循环的并行实现。它允许您使用 CPU 的更多核心(如果有可用的话)来为定义的函数执行并行 R 会话。例如:

library(doParallel)  
no_cores <- detectCores() - 1  
cl <- makeCluster(no_cores, type="FORK")  
registerDoParallel(cl)  
result <- foreach(i=10:10000) %dopar% 
getPrimeNumbers(i)

如果url存储在一个列表中,还有一个并行的lapply。

例子取自这个伟大的post:

https://www.r-bloggers.com/lets-be-faster-and-more-parallel-in-r-with-doparallel-package/amp/

希望对您有所帮助。