Stats speed up#3093
Conversation
|
Improvements step 1:
|
|
I then got Posit AI to remove the is.colour code branches. After that, the next set of improvements were:
|
|
The third set of improvements were:
|
|
The final set of improvements:
|
|
In total, this improvement and refactoring work used up about 75% of my free trial credits. |
|
Just a placeholder to note that we'll need an AI dev policy before the first time we merge code that was written with AI assistance. I can try to look up some examples, or we can just make up something we can live with. For Button Men specifically, i'd want to focus on:
(I don't use AI tools in my hobby coding for a few reasons, but whatever we agree to, i am of course also happy to do it.) |
|
Thanks for raising this. This is partly why I thought I'd evaluate AI coding openly on a piece of code that is peripherally associated with our BM project. If you could link to a policy that already exists and is easy to understand, that would be great. I'd be happy for us to adapt it if necessary, much like our Privacy Policy was adapted. |
|
I've run the transformed script and it runs within seconds, which is a huge improvement over the 6 hours that the original required. I've done a side-by-side comparison of the tables and the contents are essentially the same, the only difference is the table formatting and the truncation of decimal places when the value is a round number. I've done a diff of the .csv and .json files and they are identical. It looks like the final script does what we need it to do. Next step is to look at the code changes. |
| log.freq.matrix.limited <- log.freq.matrix | ||
| upper.limit <- 5 | ||
| log.freq.matrix.limited[log.freq.matrix.limited > upper.limit] <- upper.limit | ||
| log.freq.matrix.limited <- pmin(log2(freq.matrix), 5) |
There was a problem hiding this comment.
Makes sense.
| dt <- data.table$data.table(games.played.df, key = c('first_button_id', 'second_button_id')) | ||
| freq.dt <- dt[, .N, by = eval(data.table$key(dt))] | ||
| freq.matrix <- as.matrix(with(freq.dt, Matrix$sparseMatrix(i = first_button_id, j = second_button_id, x = N, dims = c(max.button, max.button)))) | ||
| freq.matrix <- buildFrequencyMatrix( |
There was a problem hiding this comment.
Verified that this is just refactoring out a function.
This is using inputs of the first button, the second button, and the max button ID.
| freq.dt <- dt[, .N, by = eval(data.table$key(dt))] | ||
| max_button_id <- max(button.names.df$alt_button_id) | ||
| freq.matrix <- as.matrix(with(freq.dt, Matrix$sparseMatrix(i = winner_button_id, j = loser_button_id, x = N, dims = c(max_button_id, max_button_id)))) | ||
| freq.matrix <- buildFrequencyMatrix( |
There was a problem hiding this comment.
This is using the refactored function but with inputs of the winner, loser, and max button ID.
| # Calculate the total number of games played for each matchup | ||
| n.games.matrix <- freq.matrix + t(freq.matrix) | ||
| n.games.matrix[row(n.games.matrix) == col(n.games.matrix)] <- n.games.matrix[row(n.games.matrix) == col(n.games.matrix)] / 2 | ||
| diag(n.games.matrix) <- diag(n.games.matrix) / 2 |
There was a problem hiding this comment.
Explicitly applies the halving to the diagonal as intended.
| } | ||
|
|
||
| buildColouredHtmlTable <- function(df, caption) { | ||
| # Compute cell background colours from 'Win %' and '# games played' columns |
There was a problem hiding this comment.
Colour computation is exactly my code.
|
|
||
| colour.map <- c('0' = '#ff8888', '1' = '#ffcccc', '2' = '#ffffcc', | ||
| '3' = '#ccffcc', '4' = '#88ff88', '5' = '#8888ff') | ||
| bg <- colour.map[as.character(output.colour)] |
There was a problem hiding this comment.
bg is a vector of colour strings
| bg <- colour.map[as.character(output.colour)] | ||
|
|
||
| col.names <- names(df) | ||
| header <- paste0( |
There was a problem hiding this comment.
Build a raw HTML header
| '</tr></thead>' | ||
| ) | ||
|
|
||
| rows <- paste0( |
There was a problem hiding this comment.
Build raw HTML rows
| '</tr>' | ||
| ) | ||
|
|
||
| paste0( |
There was a problem hiding this comment.
Build raw HTML table and include the HTML header and a HTML body containing the rows
| button1 = rep(button.names.df$button_name, each = nrow(button.names.df)), | ||
| button2 = button.names.df$button_name, | ||
| n.games = as.vector(n.games.matrix) | ||
| zero.idx <- which(n.games.matrix == 0, arr.ind = TRUE) |
There was a problem hiding this comment.
Find unplayed matchups directly from the button matchup frequency matrix
| button2 = button.names.df$button_name, | ||
| n.games = as.vector(n.games.matrix) | ||
| zero.idx <- which(n.games.matrix == 0, arr.ind = TRUE) | ||
| unplayed.df <- data.frame( |
There was a problem hiding this comment.
Directly create the data frame of unplayed matchups pertaining to unplayed matchups
| # Calculate the win percentage for each matchup | ||
| win.percentage.matrix <- round(100 * freq.matrix / n.games.matrix, 2) | ||
| win.percentage.matrix[row(win.percentage.matrix) == col(win.percentage.matrix)] <- NA | ||
| diag(win.percentage.matrix) <- NA |
There was a problem hiding this comment.
Explicitly sets the diagonal (mirror matches) to NA to exclude them from win percentage calculation.
| win.percentage.df.short, | ||
| file = 'win_percentage_stats.csv', | ||
| col.names = c('button_1', 'button_2', 'win_percentage', 'number_of_games'), | ||
| setNames(win.percentage.df, c('b1', 'b2', 'wp', 'ng')), |
There was a problem hiding this comment.
Inline setting of column names
| df.json <- jsonlite$toJSON(win.percentage.df.short, pretty = TRUE, digits = 2) | ||
| writeLines(df.json, paste0(save_dir(), 'win_percentage_stats.json')) | ||
|
|
||
| writeLines( |
There was a problem hiding this comment.
Inline code
There was a problem hiding this comment.
Oh, as in it's just changing the code formatting? Sure. (I wasn't sure what "inline code" meant until i looked here.)
There was a problem hiding this comment.
Yeah, it's just "inlining" multiple preparatory lines of codes into the final line.
| ', only contains played matchups') | ||
|
|
||
| return(stats.table) | ||
| return(buildColouredHtmlTable(win.percentage.df, caption)) |
There was a problem hiding this comment.
Use the new Html table generator, and delete the non-colour branch of the code.
| loser_player_name = data.df$player_name[!data.df$did_win] | ||
| ) | ||
|
|
||
| calcPlayerMatchupWinStats <- function(data.df, player.names.df) { |
There was a problem hiding this comment.
Changes in this function are effectively the same sort as in calcButtonMatchupWinStats.
| file = paste0(save_dir(), fname) | ||
| ) | ||
| path <- paste0(save_dir(), fname) | ||
| if (is.character(html.table)) { |
There was a problem hiding this comment.
New branch here deals with the raw HTML table that was created.
|
|
||
| runAll <- function() { | ||
| db <- connectToDatabase() | ||
| on.exit(RMySQL$dbDisconnect(db)) |
There was a problem hiding this comment.
Handle disconnection more carefully.
|
I've just noticed that I created the pull request from a branch of buttonmen-dev instead of my own personal repo, so I'm going to close this and recreate a new pull request from my personal repo. I'll link this pull request from it. |
I'm testing out Posit AI to see if it can speed up the chronically slow colouring-in of the stats table.
My prompt:
Its substantive responses:
and
I'm going to take a close look at what it's done here and also test it. When I understand what it's doing and have had a chance to review it, I'll remove the incomplete tag and request review.