
Calculate Strokes Gained for Every Shot
Source:R/calculate_strokes_gained.R
calculate_strokes_gained.RdScores each shot from [load_shots()] against a baseline of how many strokes a PGA Tour player needs to hole out from a given lie and distance. A shot's strokes gained is the expected strokes before it, minus the expected strokes after it, minus the strokes it cost (one, plus any penalty strokes before the next swing).
Value
A tibble with one row per stroke hit (penalty and drop rows are folded into the shot that caused them), with the columns of `shots` plus:
start_lie: tee, fairway, rough, sand, recovery (water or unknown) or greenstart_distance: Yards to the hole before the shotstrokes_used: Strokes the shot cost, including penaltiesexpected_before,expected_after: Baseline strokes to hole out before and after the shotsg: Strokes gained by the shotsg_category:"off_tee","approach","around_green"or"putt"
Details
The baseline is fit from ShotLink strokes and ships with the package. Over the 2025 and 2026 seasons, round totals built from it and adjusted with [summarise_strokes_gained()] track the PGA Tour's official strokes gained total closely (correlation 0.97 to 0.98, mean difference about 0.1 strokes per round). The split between off-the-tee and approach is less exact (correlation 0.82 to 0.92). Native area and trees count as rough, and "around the green" is defined as within 30 yards of the hole rather than of the green's edge.
Examples
shots <- tibble::tibble(
tournament_id = "R1", player_id = "1", round = 1L, course_id = "C1",
hole = 1L, par = 4L, yardage = 420L, hole_score = 4L, stroke = 1:4,
stroke_type = "STROKE", from_code = c("OTB", "OFW", "OGR", "OGR"),
distance_remaining = c(150, 10, 1, 0),
final_stroke = c(FALSE, FALSE, FALSE, TRUE)
)
calculate_strokes_gained(shots)[, c("stroke", "start_lie", "sg", "sg_category")]
#> # A tibble: 4 × 4
#> stroke start_lie sg sg_category
#> <int> <chr> <dbl> <chr>
#> 1 1 tee 0.0854 off_tee
#> 2 2 fairway 0.0661 approach
#> 3 3 green -0.229 putt
#> 4 4 green 0.0511 putt
# \donttest{
sg <- calculate_strokes_gained(load_shots(2026, "Sony"))
# }