Как мне исправить этот код R, чтобы он не был супер медленным.(Действительно новый для R) - PullRequest
0 голосов
/ 06 июня 2018

Вопрос

Как я могу исправить приведенный ниже код, чтобы он работал достаточно быстро, чтобы обрабатывать запрос на 3,2 миллиона строк, не задыхаясь в разделе вычислений, как сейчас.Быстрое здесь означает максимум часов, но не дней, и я подозреваю, что минуты на ПК, на котором он работает, являются разумными.

Проблема

У меня есть локальная база данных sql, и я пытаюсь выполнить расчет данныхновое значение и запишите его обратно в другую таблицу.Однако в настоящее время код расчета очень медленный.Я обрабатываю приблизительно 3,2 миллиона записей, так что это проблема.Все это работает в visual studio 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, которая обозначает «Процент изменения закрытия», который равен закрытию предыдущих дней, деленному на закрытие текущих дней минус 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 голосов
/ 07 июня 2018

Вы можете увеличить производительность, используя data.table следующим образом:

library(data.table)
setDT(results)
output <- results[, 
    .(pDate=pDate[-1L], pcc=(pClose/shift(pClose)-1)[-1L]), 
    by=.(Symbol, Exchange)]
0 голосов
/ 06 июня 2018

В этом коде есть два основных фактора, которые делают его медленным.Цикл 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...