如何修复此R代码,使其不会超慢。 (R真的很新)

时间:2018-06-06 15:24:50

标签: r performance

问题

如何修复下面的代码,使其运行速度足以处理320万行查询,而不会像现在这样在计算部分中进行阻塞。快速在这里意味着最多几小时而不是几天,我怀疑在它运行的PC上分钟是合理的。

问题

我有一个本地sql数据库,我试图下拉数据计算一个新值并将其写回另一个表。但是目前计算代码非常慢。我正在处理大约320万条记录,所以这是一个问题。所有这些都在视觉工作室R中运行。

我之前从未使用过R,所以我不确定是什么。事实上,我找到很好的文档来解决这个问题很困难。我怀疑是因为速度不足以及它如何减慢循环中的速度,我要么是使用列表中的索引读取数据,要么是写入不使用链接到列表的列表。

library(RODBC)

db <- odbcConnect("LocalDB")
results <- sqlQuery(db,'Select * from stockAppData;')

print("Completed loading data!")

results$pDate = as.Date(results$pDate)
results$Symbol = as.character(results$Symbol)
results$Exchange = as.character(results$Exchange)

print("Completed formating data")

#Table to temporarily hold results that will be uploaded to sql db.
table <- data.frame(Symbol = character(),
                    Exchange = character(),
                    pDate = as.Date(character()),
                    pCloseChange = double(),
                    stringsAsFactors = FALSE)
print("MADE TABLE")

#This is the loop that seems to be super slow
for (i in 2:dim(results[1])) {
    s <- results$Symbol[i]
    e <- results$Exchange[i]
    d <- results$pDate[i]
    if (results$Symbol[i] == results$Symbol[i - 1]) {
        pcc <- (results$pClose[i] / results$pClose[i - 1]) - 1
        table <- rbind(table, c(s,e,d,pcc))
    } else {
        cat("Calculated Pcgain for: ", results$Symbol[i-1] , "\n" ,sep = "")
    }
}
#Never been here because the loop takes forever
cat("Finished Calculations: returning results to DB")

columnTypes <- list(Symbol = "VARCHAR(10)", Exchange = "Varchar(5)", pDate = "date", pCloseChange = "DOUBLE PRECISION")
sqlSave(db,table,varTypes = columnTypes, rownames = FALSE,colnames = FALSE)

odbcClose(db)

其他背景

我怀疑的其他事情是缓慢但不慢的是比较我在比较因素方面遇到很多麻烦,我不知道如何正确地做到这一点。我也不一定需要双精度,但我更喜欢它,因为它是额外计算的要求。

循环逻辑

每次循环运行时,我们都会计算代表的变量pcc &#34;关闭变化百分比&#34;它等于前几天的收盘价除以当前收盘数减去1.收盘时,只需将这些信息以及我们评估当天的记录中的符号,交换和日期添加到结果表中。正如答案中所解释的那样,我在一个循环中使用了RBIND,这绝对是它变慢的原因。

if语句确保我们跳过给定符号交换组合的第一条记录。这确保我们跳过任何安全性的第一天,因为我们无法计算pcc,因为它依赖于前一天并且当前符号将是不同的安全性。请参阅下面的示例*注意输入和输出是简化示例。

示例输入

Symbol Exchange pDate pClose
APP  TSX  2018-01-13 1.00 
APP  TSX  2018-01-14 2.00
APP  NYSE 2018-01-13 2.00
APP  NYSE 2018-01-14 3.00 
APPL TSX  2018-01-13 2.00
APPL TSX  2018-01-14 3.00 

样本输出

Symbol Exchange pDate pcc
APP  TSX  2018-01-14 1.00
APP  NYSE 2018-01-14 1.00 
APPL TSX  2018-01-14 0.5

2 个答案:

答案 0 :(得分:2)

此代码中有两个主要因素使其变慢。循环中的for循环和rbind。 R是矢量化语言,因此不是一次循环列表一个项目,而是可以一次比较整个列表 绑定涉及在R中创建数据的多个副本。对象创建,删除和清理是耗时的。

#make sample data
Symbol<-rep(c("A", "B", "C"), each=10)
set.seed(1)
pClose<-rnorm(30, 100, 5)
results<-data.frame(Symbol, pClose, stringsAsFactors = FALSE)


library(dplyr)  #need dplyr's lag function
#vectorized the math
#perform all of the calcualations including the wrong ones
pcc<- (results$pClose / lag(results$pClose))-1

#Find the rows which matches the previous row
matchingSymbol = results$Symbol == lag(results$Symbol, default="")

#create the final dataframe with the filtered data
answertable<-cbind(results[matchingSymbol,], pcc[matchingSymbol])

在此解决方案中,计算是矢量化的,并且绑定仅执行一次。这段代码可以进一步改进,但是应该提供1000倍的代码加速。

一个很好的参考是“R inferno”http://www.burns-stat.com/pages/Tutor/R_inferno.pdf

答案 1 :(得分:0)

使用data.table可以获得更大的性能提升,如下所示:

library(data.table)
setDT(results)
output <- results[, 
    .(pDate=pDate[-1L], pcc=(pClose/shift(pClose)-1)[-1L]), 
    by=.(Symbol, Exchange)]