Notes: - Models are ONLY trained on Jokic career data from the present date to the 2019 season, model will ideally be trained on all players that are currently active. - H and F are currently manually selected.
#Packages
library(tidyverse)
library(jsonlite)
library(janitor)
library(dplyr)
library(DEoptim)
library(Metrics)
library(tune)
library(dlm)
library(xgboost)
pbp_jok_url <- "https://api.pbpstats.com/get-game-logs/nba?Season=2023-24,2022-23,2021-22,2020-21,2019-20,2018-19&SeasonType=Regular%2BSeason&EntityId=203999&EntityType=Player"
pbp_jok_json <- read_json(pbp_jok_url)
pbp_jok <- pbp_jok_json[["multi_row_table_data"]] %>%
bind_rows() %>%
clean_names()
pbp_jok_play_url <- "https://api.pbpstats.com/get-game-logs/nba?Season=2023-24,2022-23,2021-22,2020-21,2019-20,2018-19&SeasonType=Playoffs&EntityId=203999&EntityType=Player"
pbp_jok_play_json <- read_json(pbp_jok_play_url)
pbp_jok_play <- pbp_jok_play_json[["multi_row_table_data"]] %>%
bind_rows() %>%
clean_names()
# fix weights so that when each observation is calculated its adjusted
today <- Sys.Date()
days <- difftime(today, pbp_jok$date, unit = "days") %>%
as.data.frame() %>%
mutate_at(vars(.), funs(round(., 0)))
days$. <- as.numeric(days$.)
days <- days %>%
rename(days = '.')
jok_w_days <- cbind(pbp_jok, days) %>%
replace(is.na(.), 0)
jok_3pt <- jok_w_days %>%
filter(fg3a > 0) %>%
mutate(avg_3pt_pct = mean(fg3pct))
beta_3pt <- function(x){
rmse(jok_3pt$avg_3pt_pct, (x^(exp(jok_3pt$days))*jok_3pt$fg3pct))
}
lower <- c(0)
upper <- c(.99)
set.seed(188)
B_3pt <- DEoptim(beta_3pt , lower > 0, upper < 1, DEoptim.control(itermax = 5))
## Iteration: 1 bestvalit: 0.338873 bestmemit: 0.914971
## Iteration: 2 bestvalit: 0.338691 bestmemit: 0.966314
## Iteration: 3 bestvalit: 0.338691 bestmemit: 0.966314
## Iteration: 4 bestvalit: 0.338409 bestmemit: 0.991148
## Iteration: 5 bestvalit: 0.338409 bestmemit: 0.991148
jok_3pt <- jok_3pt %>%
mutate( fg3pct_game_estimate = jok_3pt$fg3pct * (B_3pt$optim$bestmem^(expo_decay(jok_3pt$days, start_val = 0, limit_val = 5)))) %>%
mutate(fg3pct_running_avg = cumsum(fg3pct_game_estimate) / (1:n()))
jok_2pt <- jok_w_days %>%
filter(fg2a > 0) %>%
mutate(avg_2pt_pct = mean(fg2pct))
beta_2pt <- function(x){
rmse(jok_2pt$avg_2pt_pct, (x^(exp(jok_2pt$days))*jok_2pt$fg2pct))
}
lower <- c(0)
upper <- c(.99)
set.seed(1986)
B_2pt <- DEoptim(beta_2pt , lower > 0, upper < 1, DEoptim.control(itermax = 5))
## Iteration: 1 bestvalit: 0.625306 bestmemit: 0.934639
## Iteration: 2 bestvalit: 0.625306 bestmemit: 0.934639
## Iteration: 3 bestvalit: 0.624756 bestmemit: 0.982517
## Iteration: 4 bestvalit: 0.624287 bestmemit: 0.994284
## Iteration: 5 bestvalit: 0.624287 bestmemit: 0.994284
jok_2pt <- jok_2pt %>%
mutate( fg2pct_game_estimate = jok_2pt$fg2pct * (B_2pt$optim$bestmem^(expo_decay(jok_2pt$days, start_val = 0, limit_val = 5)))) %>%
mutate(fg2pct_running_avg = cumsum(fg2pct_game_estimate) / (1:n()))
jok_assist <- jok_w_days %>%
filter(assists > 0) %>%
mutate(avg_assists = mean(assists))
beta_assist <- function(x){
rmse(jok_assist$avg_assists, (x^(exp(jok_assist$days))*jok_assist$assists))
}
lower <- c(0)
upper <- c(.99)
set.seed(194)
B_assist <- DEoptim(beta_assist , lower > 0, upper < 1, DEoptim.control(itermax = 5))
## Iteration: 1 bestvalit: 8.128287 bestmemit: 0.968275
## Iteration: 2 bestvalit: 8.128287 bestmemit: 0.968275
## Iteration: 3 bestvalit: 8.122512 bestmemit: 0.987329
## Iteration: 4 bestvalit: 8.122512 bestmemit: 0.987329
## Iteration: 5 bestvalit: 8.115084 bestmemit: 0.997644
jok_assist <- jok_assist %>%
mutate( assist_game_estimate = jok_assist$assists * (B_assist$optim$bestmem^(expo_decay(jok_assist$days, start_val = 0, limit_val = 5)))) %>%
mutate(assists_running_avg = cumsum(assist_game_estimate) / (1:n()))
#function for initialization
initializeKalmanFilter <- function(initial_state, initial_covariance, process_noise, measurement_noise){
kf <- list()
kf$state <- initial_state
kf$covariance <- initial_covariance
kf$process_noise <- process_noise
kf$measurement_noise <- measurement_noise
return(kf)
}
#function for prediction
predictKalmanFilter <- function(kf,F){
predicted_state <- F * kf$state
predicted_covariance <- F * kf$covariance * F + kf$process_noise
return(list(predicted_state = predicted_state, predicted_covariance = predicted_covariance))
}
#function for updating
updateKalmanFilter <- function(kf, predicted_state, predicted_covariance, measurement, H){
K <- predicted_covariance * H / (H * predicted_covariance * H + kf$measurement_noise)
updated_state <- predicted_state + K * (measurement - H * predicted_state)
updated_covariance <- (1 - K * H) * predicted_covariance
return(list(updated_state = updated_state , updated_covariance = updated_covariance))
}
#function to perform Kalman filtering
kalmanFilter <- function( initial_state, initial_covariance, process_noise, measurement_noise, measurements, F, H){
kf <- initializeKalmanFilter(initial_state, initial_covariance, process_noise, measurement_noise)
filtered_states <- vector(mode = "numeric", length = length(measurements))
for (i in 1:length(measurements)){
prediction <- predictKalmanFilter(kf, F)
update <- updateKalmanFilter(kf, prediction$predicted_state, prediction$predicted_covariance, measurements[i], H)
kf$state <- update$updated_state
kf$covariance <- update$updated_covariance
filtered_states[i] <- kf$state
}
return(filtered_states)
}
# 3pt% run thru Kalman filter
initial_state <- .326
initial_covariance <- 1
measurement_noise <- jok_3pt$fg3a/244
process_noise <- var(jok_3pt$fg3pct_game_estimate)
measurements <- jok_3pt$fg3pct
F <- .5
H <- .3
kalman_3pt <- kalmanFilter(initial_state, initial_covariance, process_noise, measurement_noise, measurements, F, H)
kalman_3pt <- kalman_3pt %>%
as.data.frame() %>%
rename(kalman_3pt_pct = '.')
# 2pt% run thru Kalman filter
initial_state <- .600
initial_covariance <- 1
measurement_noise <- jok_2pt$fg2a/127
process_noise <- var(jok_2pt$fg2pct_game_estimate)
measurements <- jok_2pt$fg2pct
F <- .9
H <- .75
kalman_2pt <- kalmanFilter(initial_state, initial_covariance, process_noise, measurement_noise, measurements, F, H)
kalman_2pt <- kalman_2pt %>%
as.data.frame() %>%
rename(kalman_2pt_pct = '.')
#3pt_pct combined with gradient boosted decision tree
fg3pt_pct_pred <- cbind(jok_3pt, kalman_3pt) %>%
select(kalman_3pt_pct,
fg3pct_running_avg,
avg_3pt_pct)
xg_train <- xgb.DMatrix(data = as.matrix(fg3pt_pct_pred), label = fg3pt_pct_pred$avg_3pt_pct)
x_model <- xgboost( data = xg_train, max.depth = 3 , eta = .2 , nrounds = 50, objective = "binary:logistic")
## [1] train-logloss:0.674642
## [2] train-logloss:0.662673
## [3] train-logloss:0.654884
## [4] train-logloss:0.649801
## [5] train-logloss:0.646482
## [6] train-logloss:0.644317
## [7] train-logloss:0.642906
## [8] train-logloss:0.641987
## [9] train-logloss:0.641390
## [10] train-logloss:0.641003
## [11] train-logloss:0.640752
## [12] train-logloss:0.640589
## [13] train-logloss:0.640484
## [14] train-logloss:0.640416
## [15] train-logloss:0.640372
## [16] train-logloss:0.640344
## [17] train-logloss:0.640325
## [18] train-logloss:0.640314
## [19] train-logloss:0.640306
## [20] train-logloss:0.640301
## [21] train-logloss:0.640298
## [22] train-logloss:0.640296
## [23] train-logloss:0.640295
## [24] train-logloss:0.640294
## [25] train-logloss:0.640293
## [26] train-logloss:0.640293
## [27] train-logloss:0.640293
## [28] train-logloss:0.640293
## [29] train-logloss:0.640292
## [30] train-logloss:0.640292
## [31] train-logloss:0.640292
## [32] train-logloss:0.640292
## [33] train-logloss:0.640292
## [34] train-logloss:0.640292
## [35] train-logloss:0.640292
## [36] train-logloss:0.640292
## [37] train-logloss:0.640292
## [38] train-logloss:0.640292
## [39] train-logloss:0.640292
## [40] train-logloss:0.640292
## [41] train-logloss:0.640292
## [42] train-logloss:0.640292
## [43] train-logloss:0.640292
## [44] train-logloss:0.640292
## [45] train-logloss:0.640292
## [46] train-logloss:0.640292
## [47] train-logloss:0.640292
## [48] train-logloss:0.640292
## [49] train-logloss:0.640292
## [50] train-logloss:0.640292
predict(x_model, as.matrix(fg3pt_pct_pred))
## [1] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [8] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [15] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [22] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [29] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [36] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [43] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [50] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [57] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [64] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [71] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [78] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [85] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [92] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [99] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [106] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [113] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [120] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [127] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [134] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [141] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [148] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [155] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [162] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [169] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [176] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [183] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [190] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [197] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [204] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [211] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [218] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [225] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [232] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [239] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [246] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [253] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [260] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [267] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [274] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [281] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [288] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [295] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [302] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [309] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [316] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [323] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [330] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [337] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [344] 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865 0.3388865
## [351] 0.3388865 0.3388865 0.3388865 0.3388865
#2pt_pct combined with gradient boosted decision tree
fg2pt_pct_pred <- cbind(jok_2pt, kalman_2pt) %>%
select(kalman_2pt_pct,
fg2pct_running_avg,
avg_2pt_pct)
xg_train_2pt <- xgb.DMatrix(data = as.matrix(fg2pt_pct_pred), label = fg2pt_pct_pred$avg_2pt_pct)
x_model_2pt <- xgboost( data = xg_train_2pt, max.depth = 3 , eta = .2 , nrounds = 50, objective = "binary:logistic")
## [1] train-logloss:0.681843
## [2] train-logloss:0.674550
## [3] train-logloss:0.669827
## [4] train-logloss:0.666763
## [5] train-logloss:0.664775
## [6] train-logloss:0.663486
## [7] train-logloss:0.662650
## [8] train-logloss:0.662109
## [9] train-logloss:0.661759
## [10] train-logloss:0.661533
## [11] train-logloss:0.661386
## [12] train-logloss:0.661292
## [13] train-logloss:0.661231
## [14] train-logloss:0.661192
## [15] train-logloss:0.661167
## [16] train-logloss:0.661150
## [17] train-logloss:0.661140
## [18] train-logloss:0.661133
## [19] train-logloss:0.661129
## [20] train-logloss:0.661126
## [21] train-logloss:0.661124
## [22] train-logloss:0.661123
## [23] train-logloss:0.661122
## [24] train-logloss:0.661122
## [25] train-logloss:0.661121
## [26] train-logloss:0.661121
## [27] train-logloss:0.661121
## [28] train-logloss:0.661121
## [29] train-logloss:0.661121
## [30] train-logloss:0.661121
## [31] train-logloss:0.661121
## [32] train-logloss:0.661121
## [33] train-logloss:0.661121
## [34] train-logloss:0.661121
## [35] train-logloss:0.661121
## [36] train-logloss:0.661121
## [37] train-logloss:0.661121
## [38] train-logloss:0.661121
## [39] train-logloss:0.661121
## [40] train-logloss:0.661121
## [41] train-logloss:0.661121
## [42] train-logloss:0.661121
## [43] train-logloss:0.661121
## [44] train-logloss:0.661121
## [45] train-logloss:0.661121
## [46] train-logloss:0.661121
## [47] train-logloss:0.661121
## [48] train-logloss:0.661121
## [49] train-logloss:0.661121
## [50] train-logloss:0.661121
predict(x_model_2pt, as.matrix(fg2pt_pct_pred))
## [1] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [8] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [15] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [22] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [29] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [36] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [43] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [50] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [57] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [64] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [71] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [78] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [85] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [92] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [99] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [106] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [113] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [120] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [127] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [134] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [141] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [148] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [155] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [162] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [169] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [176] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [183] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [190] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [197] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [204] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [211] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [218] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [225] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [232] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [239] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [246] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [253] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [260] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [267] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [274] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [281] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [288] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [295] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [302] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [309] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [316] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [323] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [330] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [337] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [344] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [351] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [358] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [365] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [372] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [379] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [386] 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606 0.6258606
## [393] 0.6258606 0.6258606
```