Я надеюсь, что кто-то более осведомленный, чем я, поможет оптимизировать этот код. Я пробовал несколько методов, в том числе foreach с doparallel (и snow) и компилятором, но я думаю, что могут быть более простые способы улучшить код, например, изменить фреймы данных на таблицы данных / матрицы и, возможно, вместо этого предварительно загрузить пустые объекты. конкатенации векторов в цикле.
Большинство переменных, перечисленных ниже, должны иметь возможность изменять длину в зависимости от предыдущих шагов в конвейере. Указанные размеры взяты из 1 примера, чтобы показать относительную величину.
s.ids = коэффициент длиной 66510. Не заметил разницы в скорости при изменении на вектор символов.
g.list = символьный вектор длиной 978.
l_signatures = матрица 978x66511.
d_g_up и d_g_down = небольшие фреймы данных (nx10, n в диапазоне от 5 до 200) с метаданными, относящимися к g.list
c_score_new() вычисляет счет. Это достаточно сложно, чтобы изменить его в этом сценарии. Ожидается, что e_signature будет иметь 2 столбца, один из которых состоит из g.list («идентификаторы»), а другой - как соответствующие «ранги», созданные с помощью: rank(-1 * l_signatures[,as.character(id)], ties.method = "random")
for (id in s.ids) {
e_signature <- data.frame(g.list,
rank(-1 * l_signatures[, as.character(id)],
ties.method = "random"))
colnames(e_signature) <- c("ids","rank")
d_scores <- c(d_scores, c_score_new(d_g_up$Symbol, d_g_down$Symbol, e_signature))
}
Итого, это занимает 5-10 минут для вычисления, из которых 3-5 минут связаны с генерацией e_signature, что не является сложным в вычислительном отношении. Вот где я подозреваю, что оптимизация может принести наибольшую пользу.
Если бы мы сделали цикл для генерации e_signature более эффективным способом и объединили результаты в 1 объект (978x66510) перед выполнением c_score_new(), это могло бы быть быстрее?
У меня проблемы с проработкой деталей, и я не уверен, что это лучший метод. Поэтому, прежде чем я стал преследовать этого дикого гуся, я думал, что сообщество сможет направить меня в лучшем направлении.





Наибольшее количество времени занимает rank. Можно сократить время вычислений более чем на 50%, т.е. заменить base::rank с циклом for на Rfast::colRanks, см. Ниже:
library(microbenchmark)
library(Rfast)
n <- 978
m <- 40000 #66510
x <- matrix(rnorm(n * m), ncol = m)
microbenchmark(
Initial = {
for (i in 1:ncol(x)) {
base::rank(x[, i], ties.method = "random")
}
},
Optimized = {
colRanks(x, method = "min")
},
times = 1
)
Выход:
Unit: seconds
expr min lq mean median uq max neval
Initial 8.092186 8.092186 8.092186 8.092186 8.092186 8.092186 1
Optimized 3.397526 3.397526 3.397526 3.397526 3.397526 3.397526 1
Я заметил огромный прирост производительности с точки зрения генерации df, как показано выше. Он генерируется практически мгновенно. К сожалению, когда я запускаю анализ (c_score_new ()), мне приходится брать столбцы из этого df в цикле, и я теряю 100% этого времени (все еще в сумме ~ 7,5 минут). Хотел бы я дать вам больше, чем положительный голос; Я очень ценю, что вы смотрите на это для меня!
К сожалению, без дальнейших подробностей о функции c_score_new его довольно сложно оптимизировать. Например. пожалуйста, проверьте также причину, по которой вы отправляете в цикле d_g_up$Symbol, d_g_down$Symbol - но они неизменяемы в цикле for.
Кроме того, вы можете использовать пакет data.table, который позволяет выполнять дополнительные быстрые функции, включая вычисления хешей.
Я очень ценю ваш комментарий! Вчера я пробовал это пару раз, но не увидел улучшений. Я попробовал еще раз сегодня после перехода в RMD, чтобы, надеюсь, исключить некоторые ошибки, но получил то же самое - без улучшений. Старое время: 7,4 - 7,9 минут, новое время: 7,8-7,9 минут. Я думаю, что дисперсия случайна. Я думаю, ты что-то понял. Мне нужно выяснить, чем мои объекты отличаются от ваших.