| Title: | Functions and Algorithms for Volleyball Analytics |
|---|---|
| Description: | Analytical functions for volleyball analytics, to be used in conjunction with the datavolley and peranavolley packages. |
| Authors: | Ben Raymond [aut, cre], Adrien Ickowicz [aut], openvolley.org [org] |
| Maintainer: | Ben Raymond <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.3.7 |
| Built: | 2026-05-11 09:49:10 UTC |
| Source: | https://github.com/openvolley/ovlytics |
attack_eff: (number of kills - number of errors and blocked attacks) / (number of attacks)
serve_eff: (number of aces and positive serves - number of errors and poor serves) / (number of serves)
reception_eff: (number of perfect and positive passes - number of errors and overpasses) / (number of passes)
attack_eff(evaluation, skill) serve_eff(evaluation, skill) reception_eff(evaluation, skill)attack_eff(evaluation, skill) serve_eff(evaluation, skill) reception_eff(evaluation, skill)
evaluation |
character: vector of skill evaluations ("Winning attack", "Error", etc) |
skill |
character: (optional) vector of skill values ("Attack", "Block", etc). If provided, it will be used to filter the |
A numeric scalar
## Not run: library(dplyr) x <- ovdata_example("mlafin_braslovce_nkbm", as = "parsed") plays(x) %>% dplyr::filter(skill == "Attack") %>% group_by(player_name) %>% dplyr::summarize(N_attacks = n(), att_eff = attack_eff(evaluation)) ## End(Not run)## Not run: library(dplyr) x <- ovdata_example("mlafin_braslovce_nkbm", as = "parsed") plays(x) %>% dplyr::filter(skill == "Attack") %>% group_by(player_name) %>% dplyr::summarize(N_attacks = n(), att_eff = attack_eff(evaluation)) ## End(Not run)
Attack evenness is a measure of how balanced a team's attack is. Teams that rely heavily on one or two attackers will have a relatively low evenness value, whereas teams that use all of their attackers will be higher. See https://untan.gl/attack-evenness.html for further background. Evenness is calculated for each lineup used by a team and averaged (weighting by the number of attacks that each lineup made) to get an overall evenness value. Liberos are not expected to attack, and setter attacks (dumps) are ignored. Evenness can be calculated on grouped data: by default, it is calculated by match but averaged over matches when reporting the final result.
ov_aev( x, team, rotation, reference_props = NULL, calculate_by = "match_id", report_by, min_N_attacks = 10, detail = FALSE )ov_aev( x, team, rotation, reference_props = NULL, calculate_by = "match_id", report_by, min_N_attacks = 10, detail = FALSE )
x |
data.frame: the |
team |
string: the team to calculate attack evenness for. If not provided, it will be calculated separately for all teams in |
rotation |
string: the calculation needs to know what position each player is playing, so that it can work out how many attacks that player should have made under a "perfectly even attack" scenario. This is important for middle hitters, who are usually replaced by the libero in back court and therefore cannot make attacks at those times. The
|
reference_props |
data.frame or NULL: if |
calculate_by |
character: names variables in |
report_by |
character: names of variables in
|
min_N_attacks |
integer: minimum number of attacks that must be made in order to be included in the calculations. Attacks are counted by lineup and |
detail |
logical: if |
Note that calculation by group and averaging will not generally give the same results as calculating the average result in one step (e.g. calculating for several matches and averaging those results will probably not give the same answer as calculating for all matches pooled). This is expected: say that my team under-utilizes a particular hitter in one match, and over-utilizes her in another. In both of those matches my team's attack was uneven, and so the average of those two results should return a low evenness value indicating that on average my team's attack was uneven. But if the two matches are pooled and the data analyzed all together, the under-utilization in the first match might be balanced by the over-utilization in the second match, giving a higher attack evenness.
A tibble with at least the columns "team", "aev", and "N_attacks". If detail was TRUE, additional columns will also be present (see the detail parameter)
https://untan.gl/attack-evenness.html
px <- plays(dv_read(ovdata_example())) ## for a single team ov_aev(px, rotation = "SHM", team = "GKS Katowice") ## for all teams in px, and with extra detail ov_aev(px, rotation = "SHM", detail = TRUE) ## for a single team, calculated by set number but aggregate results when reporting ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = "set_number") ## for a single team, calculated and reported by match and set number ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = c("match_id", "set_number"), report_by = c("match_id", "set_number")) ## for a single team, calculated by match and setter position, and reported by setter position px <- ov_augment_plays(px, to_add = "setters", use_existing = FALSE) ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = c("match_id", "setter_position"), report_by = "setter_position")px <- plays(dv_read(ovdata_example())) ## for a single team ov_aev(px, rotation = "SHM", team = "GKS Katowice") ## for all teams in px, and with extra detail ov_aev(px, rotation = "SHM", detail = TRUE) ## for a single team, calculated by set number but aggregate results when reporting ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = "set_number") ## for a single team, calculated and reported by match and set number ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = c("match_id", "set_number"), report_by = c("match_id", "set_number")) ## for a single team, calculated by match and setter position, and reported by setter position px <- ov_augment_plays(px, to_add = "setters", use_existing = FALSE) ov_aev(px, team = "GKS Katowice", rotation = "SHM", calculate_by = c("match_id", "setter_position"), report_by = "setter_position")
Reference proportions used in attack evenness calculations
ov_aev_reference_props()ov_aev_reference_props()
A tibble with columns player_role ("middle", "outside", "opposite", "setter", "libero"), player_front_back (whether that player is front or back court), and p_expected (the proportion of attacks that the player is expected to make under a perfectly even attack scenario)
Add information about liberos to a datavolley plays dataframe
ov_augment_liberos(x, liberos, middles)ov_augment_liberos(x, liberos, middles)
x |
data.frame: the |
liberos |
character: vector of |
middles |
character: vector of |
DataVolley (.dvw) files do not include information about the libero on court. This function adds that information where it can. It assumes that the libero replaces the back-court middle blocker, except when a middle blocker is serving.
The procedure is broadly:
all recorded ball touches are checked on a per-set basis for each team: if there were no ball touches by any libero (for a given team) during a set, it is assuumed that no libero was used in that set by that team. If ball touches were recorded only for one libero, it is assumed that only a single libero was used by that team in that set, even if that team has multiple liberos available
this information is then refined on a rally-by-rally basis: in a rally where the libero made a ball touch we can be sure that this libero was on court
The function returns a copy of x with two columns added:
the libero_on_court column will contain TRUE if a libero was on court for that data row, or FALSE if not on court, or NA if unknown
the libero_id column will contain the player_id of the libero that was on court for that data row. If no libero was on court, the value "NO_LIBERO" will be used. If a libero was known to be on court but we could not identify who it was, the value "MULTIPLE_LIBEROS" will be used
A data.frame of x augmented with columns libero_id and libero_on_court. See Details for the contents of these columns
x <- ovdata_example("190301_kats_beds", as = "parsed") ## identify our liberos and middles liberos <- c(x$meta$players_h$player_id[which(x$meta$players_h$role == "libero")], x$meta$players_v$player_id[which(x$meta$players_v$role == "libero")]) middles <- c(x$meta$players_h$player_id[which(x$meta$players_h$role == "middle")], x$meta$players_v$player_id[which(x$meta$players_v$role == "middle")]) ## infer libero info px <- ov_augment_liberos(plays(x), liberos = liberos, middles = middles)x <- ovdata_example("190301_kats_beds", as = "parsed") ## identify our liberos and middles liberos <- c(x$meta$players_h$player_id[which(x$meta$players_h$role == "libero")], x$meta$players_v$player_id[which(x$meta$players_v$role == "libero")]) middles <- c(x$meta$players_h$player_id[which(x$meta$players_h$role == "middle")], x$meta$players_v$player_id[which(x$meta$players_v$role == "middle")]) ## infer libero info px <- ov_augment_liberos(plays(x), liberos = liberos, middles = middles)
Add some extra columns to a plays object
ov_augment_plays( x, to_add = c("receiving_team", "touch_summaries", "setters"), rotation = "SHM", use_existing = TRUE )ov_augment_plays( x, to_add = c("receiving_team", "touch_summaries", "setters"), rotation = "SHM", use_existing = TRUE )
x |
data.frame: the |
to_add |
character: columns to add
|
rotation |
string: (only relevant when |
use_existing |
logical: if |
x with the extra columns added
Create a prior table from a dvw or a directory of dvw files
ov_create_history_table( dvw, play_phase = c("Reception", "Transition"), attack_by = "code", setter_position_by = "rotation", exclude_attacks = c("PR"), normalize_parameters = TRUE )ov_create_history_table( dvw, play_phase = c("Reception", "Transition"), attack_by = "code", setter_position_by = "rotation", exclude_attacks = c("PR"), normalize_parameters = TRUE )
dvw |
string: path to one or more datavolley files, a list of one or more datavolley objects, or a directory containing datavolley files |
play_phase |
character: one or both of "Reception", "Transition" |
attack_by |
string: either "code", "zone", "tempo" or "setter call" |
setter_position_by |
string: either "rotation", or "front_back" |
exclude_attacks |
character: vector of attack codes to exclude |
normalize_parameters |
logical: reduce the prior parameter values |
A list, currently with one component named "prior_table"
## use this file to create the priors hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, attack_by = "attacker_name", setter_position_by = "front_back") ## use it on another file (here, the same file for demo purposes) ## usually the history would be from a reference set of previous matches dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, attack_by = "attacker_name", attack_options = "use_history", setter_position_by = "front_back", history_table = history_table, filter_sim = TRUE) ## plot the results ov_plot_ssd(setter, overlay_set_number = TRUE) ov_plot_distribution(setter)## use this file to create the priors hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, attack_by = "attacker_name", setter_position_by = "front_back") ## use it on another file (here, the same file for demo purposes) ## usually the history would be from a reference set of previous matches dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, attack_by = "attacker_name", attack_options = "use_history", setter_position_by = "front_back", history_table = history_table, filter_sim = TRUE) ## plot the results ov_plot_ssd(setter, overlay_set_number = TRUE) ov_plot_distribution(setter)
Example DataVolley files provided as part of the ovlytics package
ov_example_file(choice = "190301_kats_beds")ov_example_file(choice = "190301_kats_beds")
choice |
string: which data file to return?
|
path to the file
myfile <- ov_example_file() x <- dv_read(myfile) summary(x)myfile <- ov_example_file() x <- dv_read(myfile) summary(x)
Kernel density estimates for volleyball heatmaps
ov_heatmap_kde( x, y, N = NULL, resolution = "coordinates", bw, n, court = "full", auto_flip = FALSE )ov_heatmap_kde( x, y, N = NULL, resolution = "coordinates", bw, n, court = "full", auto_flip = FALSE )
x |
: either a numeric vector of x-locations, or a three-column data.frame or matrix with columns |
y |
numeric: (unless |
N |
numeric: (unless |
resolution |
string: the resolution of the locations, either "coordinates" or "subzones" |
bw |
numeric: a vector of bandwidths to use in the x- and y-directions (see |
n |
integer: (scalar or a length-2 integer vector) the number of grid points in each direction. If not provided, 60 points in the x-direction and 60 (for half-court) or 120 points in the y-direction will be used |
court |
string: "full" (generate the kernel density estimate for the full court) or "lower" or "upper" (only the lower or upper half of the court) |
auto_flip |
logical: if |
A data.frame with columns x, y, and density
library(ggplot2) library(datavolley) ## Example 1 - by coordinates ## generate some fake coordinate data Na <- 20 set.seed(17) px <- data.frame(x = c(runif(Na, min = 0.4, max = 1.2), runif(Na, min = 2, max = 3)), y = c(runif(Na, min = 4.5, max = 6.6), runif(Na, min = 4.9, max = 6.6))) ## plot as points ggplot(px, aes(x, y)) + ggcourt(labels = NULL, court = "upper") + geom_point(colour = "dodgerblue") ## or as a heatmap hx <- ov_heatmap_kde(px, resolution = "coordinates", court = "upper") ggplot(hx, aes(x, y, fill = density)) + scale_fill_distiller(palette = "Purples", direction = 1, labels = NULL, name = "Attack\ndensity") + geom_raster() + ggcourt(labels = NULL, court = "upper") ## Example 2 - by subzones, with data from two attackers ## generate some fake data Na <- 20 set.seed(17) px <- data.frame(zone = sample(c(1, 5:9), Na * 2, replace = TRUE), subzone = sample(c("A", "B", "C", "D"), Na * 2, replace = TRUE), attacker = c(rep("Attacker 1", Na), rep("Attacker 2", Na))) ## convert to x, y coordinates px <- cbind(px, dv_xy(zones = px$zone, end = "upper", subzone = px$subzone)) ## plot as tiles library(dplyr) ggplot(count(px, attacker, x, y), aes(x, y, fill = n)) + geom_tile() + facet_wrap(~attacker) + ggcourt(labels = NULL, court = "upper") ## or as a heatmap, noting that we group the data by attacker first hx <- ov_heatmap_kde(group_by(px, attacker), resolution = "subzones", court = "upper") ggplot(hx, aes(x, y, fill = density)) + facet_wrap(~attacker) + scale_fill_distiller(palette = "Purples", direction = 1, labels = NULL, name = "Attack\ndensity") + geom_raster() + ggcourt(labels = NULL, court = "upper")library(ggplot2) library(datavolley) ## Example 1 - by coordinates ## generate some fake coordinate data Na <- 20 set.seed(17) px <- data.frame(x = c(runif(Na, min = 0.4, max = 1.2), runif(Na, min = 2, max = 3)), y = c(runif(Na, min = 4.5, max = 6.6), runif(Na, min = 4.9, max = 6.6))) ## plot as points ggplot(px, aes(x, y)) + ggcourt(labels = NULL, court = "upper") + geom_point(colour = "dodgerblue") ## or as a heatmap hx <- ov_heatmap_kde(px, resolution = "coordinates", court = "upper") ggplot(hx, aes(x, y, fill = density)) + scale_fill_distiller(palette = "Purples", direction = 1, labels = NULL, name = "Attack\ndensity") + geom_raster() + ggcourt(labels = NULL, court = "upper") ## Example 2 - by subzones, with data from two attackers ## generate some fake data Na <- 20 set.seed(17) px <- data.frame(zone = sample(c(1, 5:9), Na * 2, replace = TRUE), subzone = sample(c("A", "B", "C", "D"), Na * 2, replace = TRUE), attacker = c(rep("Attacker 1", Na), rep("Attacker 2", Na))) ## convert to x, y coordinates px <- cbind(px, dv_xy(zones = px$zone, end = "upper", subzone = px$subzone)) ## plot as tiles library(dplyr) ggplot(count(px, attacker, x, y), aes(x, y, fill = n)) + geom_tile() + facet_wrap(~attacker) + ggcourt(labels = NULL, court = "upper") ## or as a heatmap, noting that we group the data by attacker first hx <- ov_heatmap_kde(group_by(px, attacker), resolution = "subzones", court = "upper") ggplot(hx, aes(x, y, fill = density)) + facet_wrap(~attacker) + scale_fill_distiller(palette = "Purples", direction = 1, labels = NULL, name = "Attack\ndensity") + geom_raster() + ggcourt(labels = NULL, court = "upper")
Infer the role of each player
ov_infer_player_roles( x, target_team, method, fall_back = TRUE, setter_tip_codes = c("PP", "PR", "P2") )ov_infer_player_roles( x, target_team, method, fall_back = TRUE, setter_tip_codes = c("PP", "PR", "P2") )
x |
: a datavolley object (as returned by |
target_team |
string or function: team to report on. If this is a function, it should return |
method |
string: one of
|
fall_back |
logical: if |
setter_tip_codes |
character: vector of attack combination codes that correspond to setter tips and other attacks that do not tend to be made from a consistent start zone. Only relevant if |
The inference procedure assumes that each player plays the same role across the entire data set x. If x is drawn from multiple matches, and a player changes role from match to match, it will likely give misleading results for that player. In that case, it is probably better to run this inference on each match separately.
A data.frame with columns player_id, role, and score (the approximate confidence in the role assignment, in the range 0 to 1)
x <- ovdata_example("mlafin_braslovce_nkbm", as = "parsed") ## guess roles according to the actions that the players made rx <- ov_infer_player_roles(x, target_team = "Nova KBM Branik", method = "data")x <- ovdata_example("mlafin_braslovce_nkbm", as = "parsed") ## guess roles according to the actions that the players made rx <- ov_infer_player_roles(x, target_team = "Nova KBM Branik", method = "data")
Court plot of a real and simulated setter distribution
ov_plot_distribution( ssd, label_setters_by = "id", font_size = 11, title_wrap = NA, output = "plot" )ov_plot_distribution( ssd, label_setters_by = "id", font_size = 11, title_wrap = NA, output = "plot" )
ssd |
simulated setter distribution output as returned by |
label_setters_by |
string: either "id" or "name" |
font_size |
numeric: font size |
title_wrap |
numeric: if non- |
output |
string: either "plot" or "list" |
dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception", "Transition"), n_sim = 100, attack_by = "code") ov_plot_distribution(setter)dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception", "Transition"), n_sim = 100, attack_by = "code") ov_plot_distribution(setter)
Plot the prior table
ov_plot_history_table(history_table, team, setter_id)ov_plot_history_table(history_table, team, setter_id)
history_table |
data.frame: the |
team |
string: team name |
setter_id |
string: setter_id |
hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, setter_position_by = "front_back", normalize_parameters = FALSE) team = unique(history_table$prior_table$team)[1] setter_id = unique(history_table$prior_table$setter_id)[1] ov_plot_history_table(history_table, team, setter_id)hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, setter_position_by = "front_back", normalize_parameters = FALSE) team = unique(history_table$prior_table$team)[1] setter_id = unique(history_table$prior_table$setter_id)[1] ov_plot_history_table(history_table, team, setter_id)
Plot the rates
ov_plot_rate(ssd, team, setter_id, range = c(0.05, 0.95))ov_plot_rate(ssd, team, setter_id, range = c(0.05, 0.95))
ssd |
simulated setter distribution output as returned by |
team |
string: team name |
setter_id |
string: setter_id |
range |
vector of maximum and minimum quantile value description |
dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception", "Transition"), n_sim = 150, setter_position_by = "front_back", attack_by = "zone") team <- ssd$raw_data$meta$teams$team[1] setter_id <- ssd$raw_data$meta$players_h$player_id[which(ssd$raw_data$meta$players_h$role == "setter")][2] ov_plot_rate(ssd, team, setter_id) })dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception", "Transition"), n_sim = 150, setter_position_by = "front_back", attack_by = "zone") team <- ssd$raw_data$meta$teams$team[1] setter_id <- ssd$raw_data$meta$players_h$player_id[which(ssd$raw_data$meta$players_h$role == "setter")][2] ov_plot_rate(ssd, team, setter_id) })
Plot a simulated setter distribution sequence
ov_plot_sequence_distribution( ssd, label_setters_by = "id", font_size = 11, title_wrap = NA, split_set = FALSE, output = "plot" )ov_plot_sequence_distribution( ssd, label_setters_by = "id", font_size = 11, title_wrap = NA, split_set = FALSE, output = "plot" )
ssd |
simulated setter distribution output as returned by |
label_setters_by |
string: either "id" or "name" |
font_size |
numeric: font size |
title_wrap |
numeric: if non- |
split_set |
boolean: if |
output |
string: either "plot" or "list" |
dvw <- ovdata_example("NCA-CUB") ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception"), n_sim = 100, attack_by = "zone", setter_position_by = "front_back") ov_plot_sequence_distribution(ssd)dvw <- ovdata_example("NCA-CUB") ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = c("Reception"), n_sim = 100, attack_by = "zone", setter_position_by = "front_back") ov_plot_sequence_distribution(ssd)
Plot a simulated setter distribution
ov_plot_ssd( ssd, overlay_set_number = FALSE, label_setters_by = "name", font_size = 11 )ov_plot_ssd( ssd, overlay_set_number = FALSE, label_setters_by = "name", font_size = 11 )
ssd |
simulated setter distribution output as returned by |
overlay_set_number |
boolean: if |
label_setters_by |
string: either "id" or "name" |
font_size |
numeric: font size |
dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, n_sim = 150, attack_by = "zone") ov_plot_ssd(setter, overlay_set_number = TRUE)dvw <- ovdata_example("NCA-CUB") setter <- ov_simulate_setter_distribution(dvw = dvw, n_sim = 150, attack_by = "zone") ov_plot_ssd(setter, overlay_set_number = TRUE)
Print the prior table
ov_print_history_table(history_table, team, setter_id)ov_print_history_table(history_table, team, setter_id)
history_table |
data.frame: the |
team |
string: team name |
setter_id |
string: setter_id |
hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, attack_by = "zone") team = history_table$prior_table$team[1] setter_id = history_table$prior_table$setter_id[1] ov_print_history_table(history_table, team, setter_id)hist_dvw <- ovdata_example("NCA-CUB") history_table <- ov_create_history_table(dvw = hist_dvw, attack_by = "zone") team = history_table$prior_table$team[1] setter_id = history_table$prior_table$setter_id[1] ov_print_history_table(history_table, team, setter_id)
Print the rate table
ov_print_rate_table(ssd, team, setter_id)ov_print_rate_table(ssd, team, setter_id)
ssd |
simulated setter distribution output as returned by |
team |
string: team name |
setter_id |
string: setter_id |
dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, setter_position_by = "front_back") team <- ssd$raw_data$meta$teams$team[1] setter_id <- ssd$raw_data$meta$players_h$player_id[which(ssd$raw_data$meta$players_h$role == "setter")][2] ov_print_rate_table(ssd, team, setter_id) })dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, setter_position_by = "front_back") team <- ssd$raw_data$meta$teams$team[1] setter_id <- ssd$raw_data$meta$players_h$player_id[which(ssd$raw_data$meta$players_h$role == "setter")][2] ov_print_rate_table(ssd, team, setter_id) })
Create a summary table of a team's matches in a season
ov_season_table(xl, target_team, target_team_id, show_by = "match date")ov_season_table(xl, target_team, target_team_id, show_by = "match date")
xl |
list: list of datavolley objects (each as returned by |
target_team |
string: the name of the target team. Only one of |
target_team_id |
string: the team ID of the target team. Ignored if |
show_by |
string: either "match date" (show each match according to its date) or "filename" (show each match according to its filename. This might be useful if the match dates are being parsed incorrectly by |
A tibble with columns "Opponent", "Date" (or "File"), "Result", "Set scores", and one column for sets 1 to 5
## trivial example of a single-match "season" library(datavolley) x <- dv_read(dv_example_file()) ov_season_table(list(x), target_team = home_team(x))## trivial example of a single-match "season" library(datavolley) x <- dv_read(dv_example_file()) ov_season_table(list(x), target_team = home_team(x))
Note: analysis is done on the basis of attack actions, and simply assumes that the setter on court made the set.
ov_setter_repetition( x, setter_id, setter_name, exclude_attacks = c("PP", "PR", "P2"), exclude_negative_reception = TRUE, exclude_highballs = FALSE )ov_setter_repetition( x, setter_id, setter_name, exclude_attacks = c("PP", "PR", "P2"), exclude_negative_reception = TRUE, exclude_highballs = FALSE )
x |
data.frame: the |
setter_id |
string: (optional) the player ID of the setter to analyze (or provide |
setter_name |
string: (optional) the name of the setter to analyze (ignored if |
exclude_attacks |
character: vector of attack codes to exclude |
exclude_negative_reception |
logical: if |
exclude_highballs |
logical: if |
A data.frame with columns "team", "setter_name", "setter_id", "player_name", "player_id", "category", "opportunities", "repeats", "repeat%"
x <- plays(ovdata_example("NCA-CUB", as = "parsed")) set_reps <- ov_setter_repetition(x, setter_name = "LOLETTE RODRIGUEZ") library(ggplot2) ggplot(set_reps, aes(x = player_name, y = `repeat%`)) + geom_col() + geom_text(aes(x = player_name, label = paste0("N=", opportunities)), angle = 90, y = 100, hjust = 1, inherit.aes = FALSE) + facet_wrap(~category) + theme_bw() + theme(axis.text.x = element_text(angle = 60, vjust = 1, hjust = 1)) + labs(x = NULL, y = "Repeat percentage")x <- plays(ovdata_example("NCA-CUB", as = "parsed")) set_reps <- ov_setter_repetition(x, setter_name = "LOLETTE RODRIGUEZ") library(ggplot2) ggplot(set_reps, aes(x = player_name, y = `repeat%`)) + geom_col() + geom_text(aes(x = player_name, label = paste0("N=", opportunities)), angle = 90, y = 100, hjust = 1, inherit.aes = FALSE) + facet_wrap(~category) + theme_bw() + theme(axis.text.x = element_text(angle = 60, vjust = 1, hjust = 1)) + labs(x = NULL, y = "Repeat percentage")
Simulate a Bayesian Bandit choice for a given set of probabilities and a number of points for multiple games
ov_simulate_multiple_setter_distribution( list_dv, play_phase = c("Reception", "Transition"), n_sim = 500, priors = list(name = "beta", par1 = 1, par2 = 1), epsilon = 1, filter_sim = FALSE, attack_options = "use_data", killRate_grouping = NULL, setter_position_by = "rotation", history_table = NULL, attack_by = "code", exclude_attacks = c("PR"), rotation = "SHM", shiny_progress = NULL )ov_simulate_multiple_setter_distribution( list_dv, play_phase = c("Reception", "Transition"), n_sim = 500, priors = list(name = "beta", par1 = 1, par2 = 1), epsilon = 1, filter_sim = FALSE, attack_options = "use_data", killRate_grouping = NULL, setter_position_by = "rotation", history_table = NULL, attack_by = "code", exclude_attacks = c("PR"), rotation = "SHM", shiny_progress = NULL )
list_dv |
list: list of datavolley object as returned by |
play_phase |
character: one or both of "Reception", "Transition" |
n_sim |
integer: number of simulations |
priors |
numeric: prior distribution of the kill rate for the different attacking options |
epsilon |
numeric: reward size |
filter_sim |
logical: |
attack_options |
string: either "use_data" or "use_history" |
killRate_grouping |
string: Default to NULL, it will use 'attack by' grouping variables. Otherwise a set of additional grouping variables to calculate the kill rate. |
setter_position_by |
string: either "rotation" or "front_back" |
history_table |
list: (only if |
attack_by |
string: either "code", "zone", "tempo", "setter call", "attacker_name", "player_role" |
exclude_attacks |
character: vector of attack codes to exclude |
rotation |
string: (only relevant when |
shiny_progress |
numeric: an optional two-element vector. If not |
ov_simulate_setter_distribution()
list_dv <- list(dv_read(ovdata_example("NCA-CUB")), dv_read(ovdata_example("NCA-CUB"))) system.time({ mssd <- ov_simulate_multiple_setter_distribution(list_dv = list_dv, play_phase = "Reception", n_sim = 100, setter_position_by = "front_back") })list_dv <- list(dv_read(ovdata_example("NCA-CUB")), dv_read(ovdata_example("NCA-CUB"))) system.time({ mssd <- ov_simulate_multiple_setter_distribution(list_dv = list_dv, play_phase = "Reception", n_sim = 100, setter_position_by = "front_back") })
Simulate a Bayesian Bandit choice for a given set of probabilities and a number of points
ov_simulate_setter_distribution( dvw, play_phase = c("Reception", "Transition"), n_sim = 500, priors = list(name = "beta", par1 = 1, par2 = 1), epsilon = 1, filter_sim = FALSE, attack_options = "use_data", killRate_grouping = NULL, setter_position_by = "rotation", history_table = NULL, attack_by = "code", exclude_attacks = c("PR"), rotation = "SHM", shiny_progress = NULL )ov_simulate_setter_distribution( dvw, play_phase = c("Reception", "Transition"), n_sim = 500, priors = list(name = "beta", par1 = 1, par2 = 1), epsilon = 1, filter_sim = FALSE, attack_options = "use_data", killRate_grouping = NULL, setter_position_by = "rotation", history_table = NULL, attack_by = "code", exclude_attacks = c("PR"), rotation = "SHM", shiny_progress = NULL )
dvw |
string or datavolley: a datavolley object as returned by |
play_phase |
character: one or both of "Reception", "Transition" |
n_sim |
integer: number of simulations |
priors |
numeric: prior distribution of the kill rate for the different attacking options |
epsilon |
numeric: reward size |
filter_sim |
logical: |
attack_options |
string: either "use_data" or "use_history" |
killRate_grouping |
string: Default to NULL, it will use 'attack by' grouping variables. Otherwise a set of additional grouping variables to calculate the kill rate. |
setter_position_by |
string: either "rotation" or "front_back" |
history_table |
list: (only if |
attack_by |
string: either "code", "zone", "tempo", "setter call", "attacker_name", "player_role" |
exclude_attacks |
character: vector of attack codes to exclude |
rotation |
string: (only relevant when |
shiny_progress |
numeric: an optional two-element vector. If not |
dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, attack_by = "setter call", setter_position_by = "front_back", filter_sim = TRUE) })dvw <- ovdata_example("NCA-CUB") system.time({ ssd <- ov_simulate_setter_distribution(dvw = dvw, play_phase = "Reception", n_sim = 100, attack_by = "setter call", setter_position_by = "front_back", filter_sim = TRUE) })
Sort DataVolley attack codes
ov_sort_attack_codes(ac, by = "XV", na.last = NA)ov_sort_attack_codes(ac, by = "XV", na.last = NA)
ac |
character: character vector of attack codes to sort |
by |
string: method to use, currently only "XV" (any other value will default back to using |
na.last |
logical: passed to |
Sorted character vector
ov_sort_attack_codes(c("V5", "V1", "X6", "CF", "X5")) ## Not run: ## sorting might be useful for controlling the plot order when facetting ## a `ggplot` by attack code mydata$attack_code <- factor(mydata$attack_code, levels = ov_sort_attack_codes(unique(na.omit(mydata$attack_code)))) ggplot(mydata, ...) + facet_wrap(~attack_code) ## End(Not run)ov_sort_attack_codes(c("V5", "V1", "X6", "CF", "X5")) ## Not run: ## sorting might be useful for controlling the plot order when facetting ## a `ggplot` by attack code mydata$attack_code <- factor(mydata$attack_code, levels = ov_sort_attack_codes(unique(na.omit(mydata$attack_code)))) ggplot(mydata, ...) + facet_wrap(~attack_code) ## End(Not run)
Table of a simulated multi-game setter distribution sequence
ov_table_mssd( mssd, label_setters_by = "name", team = NULL, nrows = 50, groupBy = TRUE )ov_table_mssd( mssd, label_setters_by = "name", team = NULL, nrows = 50, groupBy = TRUE )
mssd |
simulated multi-game setter distribution output as returned by |
label_setters_by |
string: either "id" or "name" |
team |
NULL or string: if non-NULL, show sequence just for this team name |
nrows |
integer: number of rows per page in the table |
groupBy |
boolean: if TRUE, will group the rows by Opponent |
## Not run: list_dv <- list(dv_read(ovdata_example("NCA-CUB"))) # would normally be multiple games mssd <- ov_simulate_multiple_setter_distribution(list_dv = list_dv, play_phase = c("Reception", "Transition"), attack_by = "attacker_name", n_sim = 100, setter_position_by = "front_back") res <- ov_table_mssd(mssd, team = "NICARAGUA") ## End(Not run)## Not run: list_dv <- list(dv_read(ovdata_example("NCA-CUB"))) # would normally be multiple games mssd <- ov_simulate_multiple_setter_distribution(list_dv = list_dv, play_phase = c("Reception", "Transition"), attack_by = "attacker_name", n_sim = 100, setter_position_by = "front_back") res <- ov_table_mssd(mssd, team = "NICARAGUA") ## End(Not run)
Analytical functions for volleyball analytics, to be used in conjunction with the datavolley and peranavolley packages.
Maintainer: Ben Raymond [email protected]
Authors:
Adrien Ickowicz
Other contributors:
openvolley.org [originator]
Useful links:
Report bugs at https://github.com/openvolley/ovlytics/issues