Из комментариев мы узнали, что основной проблемой вопроса является вычисление Эло оценок .Без большого количества информации, я ожидаю, что проблема заключается в оптимизации кода для скорости.
Вместо использования функции apply
над for loop
можно добиться значительного улучшения скорости, сначала преобразовав рейтинги в структуры player 1 vs player 2
и преобразовав код для использования векторизованных вычислений.Возьмите пример реализации ниже:
Probability <- function(R1, R2)
1 / (1 + 10^((R1 - R2)/400))
EloRating <- function(R1, R2, K, d){
P1 <- Probability(R2, R1)
P2 <- Probability(R1, R2)
index <- d == 1 #Which matches did Player 1 win?
#Use that d is 0 and 1's, and !d is 1 and 0's (reverse of d)
R1 <- R1 + K * (d - P1)
R2 <- R2 + K * (!d - P1)
#output updated ratings
return(list(Rating1 = R1, Rating2 = R2))
}
Обратите внимание на отсутствие функций for loop
и apply
, таких как sapply
.
Этот фрагмент кода высоко оптимизирован, поскольку Probability
может принимать любые 2 вектора и возвращать вектор одинаковой длины, используя только встроенные функции R
, которые сами реализованы в оптимизированном * 1018.* или Fortran
код.
Сама функция EloRating
также очень оптимизирована.Сначала мы рассчитываем вероятность (при предположении нормальности, я догадываюсь?) Выигрыша любого из игроков.Далее я предполагаю, что задан входной вектор d
побед, для которого d[i]==1
указывает на то, что игрок 1 выиграл матч против игрока 2, а любой другой результат является обратным.
Мне нравится, когда выигрыш игрока 1 помечен как 1, а выигрыш игрока 2 помечен как 0, поэтому я использую d==1
, чтобы убедиться, что d
содержит только 1 (TRUE
) и 0 * 1030.*.
Когда я убедился в этом, я могу злоупотреблять тем, что логический вектор можно инвертировать, используя !d
, изменяя, какие элементы равны 1, а какие - 0.Таким образом, я могу выполнить все изменения рейтинга одновременно, используя только 2 строки кода.
Для небольшого тестирования скорости, давайте запустим микробенчмарк для 1000 наблюдаемых совпадений
set.seed(1)
n <- 1000
R1 <- rnorm(n, 1000, 50)
R2 <- rnorm(n, 1000, 50)
wins <- sample(1:2, n, replace = TRUE)
microbenchmark::microbenchmark(EloRating(R1, R2, 40, wins), times = 1e3)
#output
Unit: microseconds
expr min lq mean median uq max neval
EloRating(R1, R2, 40, wins) 289.983 291.87 305.2853 293.381 309.239 626.03 1000
Обратите внимание на среднее времясоставляет 2.93 * 1e-6
секунд на итерацию для 1000 игроков.
Отказ от ответственности
Я просто конвертировал код из GeeksforGeeks , не задумываясь о его правильности.Я не несу ответственности за любые ошибки в коде, и я предлагаю проверить известные результаты перед его использованием.