I want your feedback to make the book better for you and other readers. If you find typos, errors, or places where the text may be improved, please let me know. The best ways to provide feedback are by GitHub or hypothes.is annotations.
Opening an issue or submitting a pull request on GitHub: https://github.com/isaactpetersen/Fantasy-Football-Analytics-Textbook
Adding an annotation using hypothes.is. To add an annotation, select some text and then click the symbol on the pop-up menu. To see the annotations of others, click the symbol in the upper right-hand corner of the page.
18 Mythbusters: Putting Fantasy Football Beliefs/Anecdotes to the Test
18.1 Getting Started
18.1.1 Load Packages
18.1.2 Specify Package Options
18.1.3 Load Data
We created the player_stats_weekly.RData
and player_stats_seasonal.RData
objects in Section 4.4.3.
18.2 Do Players Perform Better in their Contract Year?
Considerable speculation exists regarding whether players perform better in their last year of their contract (i.e., their “contract year”). Fantasy football talking heads and commentators frequently discuss the benefit of selecting players who are in their contract year, because it supposedly means that player has more motivation to perform well so they get a new contract and get paid more. To our knowledge, no peer-reviewed studies have examined this question for football players. One study found that National Basketball Association (NBA) players improved in field goal percentage, points, and player efficiency rating (but not other statistics: rebounds, assists, steals, or blocks) from their pre-contract year to their contract year, and that Major League Baseball (MLB) players improved in runs batted in (RBIs; but not other statistics: batting average, slugging percentage, on base percentage, home runs, fielding percentage) from their pre-contract year to their contract year (White & Sheldon, 2014). Other casual analyses have been examined contract-year performance of National Football League (NFL) players, including articles in 2012 (archived here) and 2022 (archived here).
Let’s examine the question empirically. In order to do that, we have to make some assumptions/constraints. In this example, we will make the following constraints:
- We will determine a player’s contract year programmatically based on the year the contract was signed. For instance, if a player signed a 3-year contract in 2015, their contract would expire in 2018, and thus their contract year would be 2017. Note: this is a coarse way of determining a player’s contract year because it could depend on when during the year the player’s contract is signed. If we were submitting this analysis as a paper to a scientific journal, it would be important to verify each player’s contract year.
- We will examine performance in all seasons since 2011, beginning when most data for player contracts are available.
- For maximum statistical power to detect an effect if a contract year effect exists, we will examine all seasons for a player (since 2011), not just their contract year and their pre-contract year.
- To ensure a more fair, apples-to-apples comparison of the games in which players played, we will examine per-game performance (except for yards per carry, which is based on \(\frac{\text{rushing yards}}{\text{carries}}\) from the entire season).
- We will examine regular season games only (no postseason).
- To ensure we do not make generalization about a player’s performance in a season from a small sample, the player has to play at least 5 games in a given season for that player–season combination to be included in analysis.
For analysis, the same player contributes multiple observations of performance (i.e., multiple seasons) due to the longitudinal nature of the data. Inclusion of multiple data points from the same player would violate the assumption of multiple regression that all observations are independent. Thus, we use mixed-effects models that allow nonindependent observations. In our mixed-effects models, we include a random intercept for each player, to allow our model to account for players’ differing level of performance. We examine two mixed-effects models for each outcome variable: one model that accounts for the effects of age and experience, and one model that does not.
The model that does not account for the effects of age and experience includes:
- random intercepts to allow the model to estimate a different starting point for each player
- a fixed effect for whether the player is in a contract year
The model that accounts for the effects of age and experience includes:
- random intercepts to allow the model to estimate a different starting point for each player
- random linear slopes (i.e., random effect of linear age) to allow the model to estimate a different form of change for each player
- a fixed quadratic effect of age to allow for curvilinear effects
- a fixed effect of experience
- a fixed effect for whether the player is in a contract year
Code
# Subset to remove players without a year signed
nfl_playerContracts_subset <- nfl_playerContracts %>%
dplyr::filter(!is.na(year_signed) & year_signed != 0)
# Determine the contract year for a given contract
nfl_playerContracts_subset$contractYear <- nfl_playerContracts_subset$year_signed + nfl_playerContracts_subset$years - 1
# Arrange contracts by player and year_signed
nfl_playerContracts_subset <- nfl_playerContracts_subset %>%
dplyr::group_by(player, position) %>%
dplyr::arrange(player, position, -year_signed) %>%
dplyr::ungroup()
# Determine if the player played in the original contract year
nfl_playerContracts_subset <- nfl_playerContracts_subset %>%
dplyr::group_by(player, position) %>%
dplyr::mutate(
next_contract_start = lag(year_signed)) %>%
dplyr::ungroup() %>%
dplyr::mutate(
played_in_contract_year = ifelse(
is.na(next_contract_start) | contractYear < next_contract_start,
TRUE,
FALSE))
# Check individual players
#nfl_playerContracts_subset %>%
# dplyr::filter(player == "Aaron Rodgers") %>%
# dplyr::select(player:years, contractYear, next_contract_start, played_in_contract_year)
#
#nfl_playerContracts_subset %>%
# dplyr::filter(player %in% c("Jared Allen", "Aaron Rodgers")) %>%
# dplyr::select(player:years, contractYear, next_contract_start, played_in_contract_year)
# Subset data
nfl_playerContractYears <- nfl_playerContracts_subset %>%
dplyr::filter(played_in_contract_year == TRUE) %>%
dplyr::filter(position %in% c("QB","RB","WR","TE")) %>%
dplyr::select(player, position, team, contractYear) %>%
dplyr::mutate(merge_name = nflreadr::clean_player_names(player, lowercase = TRUE)) %>%
dplyr::rename(season = contractYear) %>%
dplyr::mutate(contractYear = 1)
# Merge with weekly and seasonal stats data
player_stats_weekly_offense <- player_stats_weekly %>%
dplyr::filter(position_group %in% c("QB","RB","WR","TE")) %>%
dplyr::mutate(merge_name = nflreadr::clean_player_names(player_display_name, lowercase = TRUE))
#nfl_actualStats_offense_seasonal <- nfl_actualStats_offense_seasonal %>%
# mutate(merge_name = nflreadr::clean_player_names(player_display_name, lowercase = TRUE))
player_statsContracts_offense_weekly <- dplyr::full_join(
player_stats_weekly_offense,
nfl_playerContractYears,
by = c("merge_name", "position_group" = "position", "season")
) %>%
dplyr::filter(position_group %in% c("QB","RB","WR","TE"))
#player_statsContracts_offense_seasonal <- full_join(
# player_stats_seasonal_offense,
# nfl_playerContractYears,
# by = c("merge_name", "position_group" = "position", "season")
#) %>%
# filter(position_group %in% c("QB","RB","WR","TE"))
player_statsContracts_offense_weekly$contractYear[which(is.na(player_statsContracts_offense_weekly$contractYear))] <- 0
#player_statsContracts_offense_seasonal$contractYear[which(is.na(player_statsContracts_offense_seasonal$contractYear))] <- 0
#player_statsContracts_offense_weekly$contractYear <- factor(
# player_statsContracts_offense_weekly$contractYear,
# levels = c(0, 1),
# labels = c("no", "yes"))
#player_statsContracts_offense_seasonal$contractYear <- factor(
# player_statsContracts_offense_seasonal$contractYear,
# levels = c(0, 1),
# labels = c("no", "yes"))
player_statsContracts_offense_weekly <- player_statsContracts_offense_weekly %>%
dplyr::arrange(merge_name, season, season_type, week)
#player_statsContracts_offense_seasonal <- player_statsContracts_offense_seasonal %>%
# arrange(merge_name, season)
player_statsContractsSubset_offense_weekly <- player_statsContracts_offense_weekly %>%
dplyr::filter(season_type == "REG")
#table(nfl_playerContracts$year_signed) # most contract data is available beginning in 2011
# Calculate Per Game Totals
player_statsContracts_seasonal <- player_statsContractsSubset_offense_weekly %>%
dplyr::group_by(player_id, season) %>%
dplyr::summarise(
player_display_name = petersenlab::Mode(player_display_name),
position_group = petersenlab::Mode(position_group),
age = min(age, na.rm = TRUE),
years_of_experience = min(years_of_experience, na.rm = TRUE),
rushing_yards = sum(rushing_yards, na.rm = TRUE), # season total
carries = sum(carries, na.rm = TRUE), # season total
rushing_epa = mean(rushing_epa, na.rm = TRUE),
receiving_yards = mean(receiving_yards, na.rm = TRUE),
receiving_epa = mean(receiving_epa, na.rm = TRUE),
fantasyPoints = sum(fantasyPoints, na.rm = TRUE), # season total
contractYear = mean(contractYear, na.rm = TRUE),
games = n(),
.groups = "drop_last"
) %>%
dplyr::mutate(
player_id = as.factor(player_id),
ypc = rushing_yards / carries,
contractYear = factor(
contractYear,
levels = c(0, 1),
labels = c("no", "yes")
))
player_statsContracts_seasonal[sapply(player_statsContracts_seasonal, is.infinite)] <- NA
player_statsContracts_seasonal$ageCentered20 <- player_statsContracts_seasonal$age - 20
player_statsContracts_seasonal$ageCentered20Quadratic <- player_statsContracts_seasonal$ageCentered20 ^ 2
# Merge with seasonal fantasy points data
18.2.1 QB
First, we prepare the data by merging and performing additional processing:
Code
# Merge with QBR data
nfl_espnQBR_weekly$merge_name <- paste(nfl_espnQBR_weekly$name_first, nfl_espnQBR_weekly$name_last, sep = " ") %>%
nflreadr::clean_player_names(., lowercase = TRUE)
nfl_contractYearQBR_weekly <- nfl_playerContractYears %>%
dplyr::filter(position == "QB") %>%
dplyr::full_join(
.,
nfl_espnQBR_weekly,
by = c("merge_name","team","season")
)
nfl_contractYearQBR_weekly$contractYear[which(is.na(nfl_contractYearQBR_weekly$contractYear))] <- 0
#nfl_contractYearQBR_weekly$contractYear <- factor(
# nfl_contractYearQBR_weekly$contractYear,
# levels = c(0, 1),
# labels = c("no", "yes"))
nfl_contractYearQBR_weekly <- nfl_contractYearQBR_weekly %>%
dplyr::arrange(merge_name, season, season_type, game_week)
nfl_contractYearQBRsubset_weekly <- nfl_contractYearQBR_weekly %>%
dplyr::filter(season_type == "Regular") %>%
dplyr::arrange(merge_name, season, season_type, game_week) %>%
mutate(
player = coalesce(player, name_display),
position = "QB") %>%
group_by(merge_name, player_id) %>%
fill(player, .direction = "downup")
# Merge with age and experience
nfl_contractYearQBRsubset_weekly <- player_statsContractsSubset_offense_weekly %>%
dplyr::filter(position == "QB") %>%
dplyr::select(merge_name, season, week, age, years_of_experience, fantasyPoints) %>%
full_join(
nfl_contractYearQBRsubset_weekly,
by = c("merge_name","season", c("week" = "game_week"))
) %>% select(player_id, season, week, player, everything()) %>%
arrange(player_id, season, week)
#hist(nfl_contractYearQBRsubset_weekly$qb_plays) # players have at least 20 dropbacks per game
# Calculate Per Game Totals
nfl_contractYearQBR_seasonal <- nfl_contractYearQBRsubset_weekly %>%
dplyr::group_by(merge_name, season) %>%
dplyr::summarise(
age = min(age, na.rm = TRUE),
years_of_experience = min(years_of_experience, na.rm = TRUE),
qbr = mean(qbr_total, na.rm = TRUE),
pts_added = mean(pts_added, na.rm = TRUE),
epa_pass = mean(pass, na.rm = TRUE),
qb_plays = sum(qb_plays, na.rm = TRUE), # season total
fantasyPoints = sum(fantasyPoints, na.rm = TRUE), # season total
contractYear = mean(contractYear, na.rm = TRUE),
games = n(),
.groups = "drop_last"
) %>%
dplyr::mutate(
contractYear = factor(
contractYear,
levels = c(0, 1),
labels = c("no", "yes")
))
nfl_contractYearQBR_seasonal[sapply(nfl_contractYearQBR_seasonal, is.infinite)] <- NA
nfl_contractYearQBR_seasonal$ageCentered20 <- nfl_contractYearQBR_seasonal$age - 20
nfl_contractYearQBR_seasonal$ageCentered20Quadratic <- nfl_contractYearQBR_seasonal$ageCentered20 ^ 2
nfl_contractYearQBR_seasonal <- nfl_contractYearQBR_seasonal %>%
group_by(merge_name) %>%
mutate(player_id = as.factor(as.character(cur_group_id())))
nfl_contractYearQBRsubset_seasonal <- nfl_contractYearQBR_seasonal %>%
dplyr::filter(
games >= 5, # keep only player-season combinations in which QBs played at least 5 games
season >= 2011) # keep only seasons since 2011 (when most contract data are available)
Then, we analyze the data. Below is a mixed model that examines whether a player has a higher QBR per game when they are in a contract year compared to when they are not in a contract year.
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: qbr ~ contractYear + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 8905.7
Scaled residuals:
Min 1Q Median 3Q Max
-3.2658 -0.5446 0.0914 0.5732 3.2578
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 111.6 10.56
Residual 198.6 14.09
Number of obs: 1063, groups: player_id, 253
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 44.2363 0.8738 231.4295 50.624 <2e-16 ***
contractYearyes 0.2432 1.2010 950.6905 0.202 0.84
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.241
R2m R2c
[1,] 2.915379e-05 0.359728
contractYear emmean SE df lower.CL upper.CL
no 44.2 0.874 262 42.5 46
yes 44.5 1.300 752 41.9 47
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: qbr ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 8833
Scaled residuals:
Min 1Q Median 3Q Max
-3.3838 -0.5220 0.0928 0.5506 3.2853
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 135.206 11.628
ageCentered20 0.433 0.658 -0.41
Residual 191.543 13.840
Number of obs: 1055, groups: player_id, 249
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 39.47167 2.29478 174.07664 17.201 < 2e-16 ***
contractYearyes 0.31817 1.23969 946.72121 0.257 0.79750
ageCentered20 0.85795 0.64998 265.02249 1.320 0.18799
ageCentered20Quadratic -0.07527 0.02354 98.16828 -3.197 0.00187 **
years_of_experience 0.61694 0.54694 289.48076 1.128 0.26026
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.055
ageCentrd20 -0.734 -0.059
agCntrd20Qd 0.764 0.055 -0.628
yrs_f_xprnc 0.100 -0.043 -0.662 -0.120
R2m R2c
[1,] 0.01316462 0.3966867
contractYear emmean SE df lower.CL upper.CL
no 44.1 0.916 240 42.3 45.9
yes 44.4 1.330 706 41.8 47.0
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: pts_added ~ contractYear + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4855.8
Scaled residuals:
Min 1Q Median 3Q Max
-4.7107 -0.4882 0.0804 0.5366 4.4282
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 2.570 1.603
Residual 4.332 2.081
Number of obs: 1063, groups: player_id, 253
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -0.85472 0.13129 219.85741 -6.510 5.02e-10 ***
contractYearyes -0.06893 0.17768 939.65392 -0.388 0.698
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.237
R2m R2c
[1,] 0.0001052534 0.3723735
contractYear emmean SE df lower.CL upper.CL
no -0.855 0.131 262 -1.11 -0.596
yes -0.924 0.194 745 -1.31 -0.542
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: pts_added ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4825.5
Scaled residuals:
Min 1Q Median 3Q Max
-4.8624 -0.4856 0.0839 0.5194 4.4052
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 3.54809 1.8836
ageCentered20 0.01153 0.1074 -0.55
Residual 4.18409 2.0455
Number of obs: 1055, groups: player_id, 249
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -1.597976 0.347877 168.940692 -4.594 8.49e-06 ***
contractYearyes -0.076689 0.183346 936.388386 -0.418 0.67584
ageCentered20 0.100485 0.097484 270.759302 1.031 0.30356
ageCentered20Quadratic -0.011106 0.003522 100.614226 -3.153 0.00213 **
years_of_experience 0.133743 0.081042 281.434965 1.650 0.10000
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.055
ageCentrd20 -0.737 -0.060
agCntrd20Qd 0.761 0.059 -0.638
yrs_f_xprnc 0.108 -0.044 -0.663 -0.107
R2m R2c
[1,] 0.0139585 0.4014263
contractYear emmean SE df lower.CL upper.CL
no -0.846 0.136 242 -1.11 -0.579
yes -0.923 0.197 708 -1.31 -0.536
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: epa_pass ~ contractYear + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4533.4
Scaled residuals:
Min 1Q Median 3Q Max
-3.0315 -0.5088 0.0398 0.5664 4.3662
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 2.454 1.566
Residual 3.049 1.746
Number of obs: 1063, groups: player_id, 253
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 1.0733 0.1218 239.6969 8.810 2.58e-16 ***
contractYearyes 0.4241 0.1504 928.0954 2.821 0.0049 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.214
R2m R2c
[1,] 0.004973305 0.4486446
contractYear emmean SE df lower.CL upper.CL
no 1.07 0.122 263 0.833 1.31
yes 1.50 0.172 699 1.159 1.84
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
mixedModelAge_epaPass <- lmerTest::lmer(
epa_pass ~ contractYear + ageCentered20 + ageCentered20Quadratic + years_of_experience + (1 | player_id), # removed random slopes to address convergence issue
data = nfl_contractYearQBR_seasonal,
control = lmerControl(optimizer = "bobyqa")
)
summary(mixedModelAge_epaPass)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: epa_pass ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4496.2
Scaled residuals:
Min 1Q Median 3Q Max
-3.1285 -0.5002 0.0415 0.5381 4.2903
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 2.426 1.557
Residual 2.993 1.730
Number of obs: 1055, groups: player_id, 249
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 3.315e-01 2.817e-01 9.490e+02 1.177 0.23962
contractYearyes 2.468e-01 1.552e-01 9.498e+02 1.590 0.11219
ageCentered20 2.496e-03 8.169e-02 6.844e+02 0.031 0.97563
ageCentered20Quadratic -5.555e-03 2.704e-03 1.010e+03 -2.054 0.04022 *
years_of_experience 1.935e-01 7.206e-02 3.935e+02 2.685 0.00756 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.063
ageCentrd20 -0.711 -0.055
agCntrd20Qd 0.740 0.057 -0.574
yrs_f_xprnc 0.141 -0.048 -0.709 -0.133
R2m R2c
[1,] 0.03051935 0.4645375
contractYear emmean SE df lower.CL upper.CL
no 1.19 0.124 260 0.942 1.43
yes 1.43 0.173 687 1.094 1.77
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: fantasyPoints ~ contractYear + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 12460.3
Scaled residuals:
Min 1Q Median 3Q Max
-3.8564 -0.5600 -0.0851 0.6047 2.8720
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 5791 76.1
Residual 5041 71.0
Number of obs: 1063, groups: player_id, 253
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 103.696 5.628 293.908 18.424 < 2e-16 ***
contractYearyes -25.186 6.171 935.684 -4.081 4.86e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.189
R2m R2c
[1,] 0.008874502 0.5387338
contractYear emmean SE df lower.CL upper.CL
no 103.7 5.63 262 92.6 114.8
yes 78.5 7.53 635 63.7 93.3
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
mixedModelAge_fantasyPtsPass <- lmerTest::lmer(
fantasyPoints ~ contractYear + ageCentered20 + ageCentered20Quadratic + years_of_experience + (1 | player_id), # removed random slopes to address convergence issue
data = nfl_contractYearQBR_seasonal,
control = lmerControl(optimizer = "bobyqa")
)
summary(mixedModelAge_fantasyPtsPass)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula:
fantasyPoints ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 | player_id)
Data: nfl_contractYearQBR_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 12337.5
Scaled residuals:
Min 1Q Median 3Q Max
-3.8942 -0.5618 -0.0743 0.6125 2.7478
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 5764 75.92
Residual 4923 70.17
Number of obs: 1055, groups: player_id, 249
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 126.8448 12.0072 955.8120 10.564 < 2e-16 ***
contractYearyes -20.8005 6.3731 948.2146 -3.264 0.001139 **
ageCentered20 -11.7659 3.5535 760.2272 -3.311 0.000973 ***
ageCentered20Quadratic -0.1167 0.1117 994.4649 -1.044 0.296722
years_of_experience 12.8752 3.2246 500.9729 3.993 7.51e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.065
ageCentrd20 -0.693 -0.052
agCntrd20Qd 0.713 0.054 -0.536
yrs_f_xprnc 0.172 -0.045 -0.741 -0.134
R2m R2c
[1,] 0.05246165 0.5634855
contractYear emmean SE df lower.CL upper.CL
no 104.3 5.74 262 93.0 115.6
yes 83.5 7.56 621 68.7 98.4
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
18.2.2 RB
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: ypc ~ contractYear + (1 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 5973.3
Scaled residuals:
Min 1Q Median 3Q Max
-7.9077 -0.3904 0.0127 0.3862 14.7586
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 0.4971 0.7051
Residual 1.9117 1.3826
Number of obs: 1630, groups: player_id, 509
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 3.895e+00 5.279e-02 4.969e+02 73.779 <2e-16 ***
contractYearyes 2.525e-02 8.555e-02 1.568e+03 0.295 0.768
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.372
R2m R2c
[1,] 5.050989e-05 0.2064248
contractYear emmean SE df lower.CL upper.CL
no 3.89 0.0528 602 3.79 4.00
yes 3.92 0.0822 1202 3.76 4.08
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: ypc ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 5956.1
Scaled residuals:
Min 1Q Median 3Q Max
-7.6944 -0.3728 0.0039 0.3912 14.1281
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 0.32825 0.5729
ageCentered20 0.01158 0.1076 -0.30
Residual 1.84189 1.3572
Number of obs: 1628, groups: player_id, 507
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 4.222e+00 1.776e-01 6.717e+02 23.778 <2e-16 ***
contractYearyes 1.265e-01 9.244e-02 1.505e+03 1.368 0.171
ageCentered20 -7.950e-02 6.140e-02 7.141e+02 -1.295 0.196
ageCentered20Quadratic -3.626e-03 4.461e-03 3.764e+02 -0.813 0.417
years_of_experience 5.539e-02 3.738e-02 4.306e+02 1.482 0.139
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.157
ageCentrd20 -0.872 -0.173
agCntrd20Qd 0.820 0.123 -0.824
yrs_f_xprnc -0.070 -0.074 -0.292 -0.215
R2m R2c
[1,] 0.02173972 0.2602485
contractYear emmean SE df lower.CL upper.CL
no 3.85 0.0561 519 3.74 3.96
yes 3.97 0.0860 1163 3.80 4.14
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: rushing_epa ~ contractYear + (1 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4697.5
Scaled residuals:
Min 1Q Median 3Q Max
-4.5842 -0.5074 0.0844 0.5913 3.4362
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 0.1091 0.3303
Residual 0.9480 0.9737
Number of obs: 1630, groups: player_id, 509
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -0.65276 0.03262 612.67321 -20.011 <2e-16 ***
contractYearyes 0.04100 0.05822 1626.69621 0.704 0.481
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.429
R2m R2c
[1,] 0.0003033165 0.1034567
contractYear emmean SE df lower.CL upper.CL
no -0.653 0.0326 617 -0.717 -0.589
yes -0.612 0.0532 1124 -0.716 -0.507
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: rushing_epa ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 4704.4
Scaled residuals:
Min 1Q Median 3Q Max
-4.6207 -0.5022 0.0780 0.5854 3.4459
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 0.228839 0.47837
ageCentered20 0.002858 0.05346 -0.73
Residual 0.927374 0.96300
Number of obs: 1628, groups: player_id, 507
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -6.448e-01 1.230e-01 3.952e+02 -5.243 2.58e-07 ***
contractYearyes 7.553e-02 6.173e-02 1.440e+03 1.224 0.2213
ageCentered20 4.237e-02 4.081e-02 3.764e+02 1.038 0.2999
ageCentered20Quadratic -1.401e-03 2.871e-03 1.958e+02 -0.488 0.6261
years_of_experience -4.881e-02 2.240e-02 4.306e+02 -2.179 0.0298 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.154
ageCentrd20 -0.886 -0.197
agCntrd20Qd 0.833 0.153 -0.856
yrs_f_xprnc -0.060 -0.059 -0.268 -0.193
R2m R2c
[1,] 0.006806377 0.1273214
contractYear emmean SE df lower.CL upper.CL
no -0.664 0.0336 552 -0.730 -0.598
yes -0.589 0.0553 1111 -0.697 -0.480
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: fantasyPoints ~ contractYear + (1 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 18806.7
Scaled residuals:
Min 1Q Median 3Q Max
-3.0576 -0.5022 -0.1804 0.3944 3.8668
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 2298 47.93
Residual 2109 45.92
Number of obs: 1724, groups: player_id, 525
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 64.887 2.543 630.937 25.513 < 2e-16 ***
contractYearyes -11.289 2.998 1490.473 -3.765 0.000173 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.238
R2m R2c
[1,] 0.005379707 0.5239906
contractYear emmean SE df lower.CL upper.CL
no 64.9 2.54 572 59.9 69.9
yes 53.6 3.44 1223 46.8 60.4
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula:
fantasyPoints ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsRB_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 18667.3
Scaled residuals:
Min 1Q Median 3Q Max
-3.2611 -0.4880 -0.1577 0.3980 3.6091
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 4600.19 67.825
ageCentered20 39.61 6.294 -0.76
Residual 1816.43 42.620
Number of obs: 1722, groups: player_id, 523
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 57.4155 7.3822 669.8502 7.778 2.80e-14 ***
contractYearyes -6.4763 3.1078 1459.9084 -2.084 0.0373 *
ageCentered20 -0.6904 2.5240 872.0844 -0.274 0.7845
ageCentered20Quadratic -0.8427 0.1574 459.6570 -5.353 1.37e-07 ***
years_of_experience 10.7026 1.6790 619.9360 6.374 3.59e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.176
ageCentrd20 -0.848 -0.171
agCntrd20Qd 0.748 0.156 -0.770
yrs_f_xprnc 0.155 -0.075 -0.505 -0.090
R2m R2c
[1,] 0.07533867 0.604956
contractYear emmean SE df lower.CL upper.CL
no 63.9 2.56 573 58.8 68.9
yes 57.4 3.42 1200 50.7 64.1
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
18.2.3 WR/TE
Code
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: receiving_yards ~ contractYear + (1 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 30379.4
Scaled residuals:
Min 1Q Median 3Q Max
-4.8618 -0.5297 -0.1068 0.5113 4.5629
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 280.0 16.73
Residual 184.1 13.57
Number of obs: 3560, groups: player_id, 1034
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 25.1047 0.6073 1237.9557 41.336 < 2e-16 ***
contractYearyes -3.4995 0.5868 3007.2060 -5.964 2.75e-09 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.233
R2m R2c
[1,] 0.005322244 0.6053999
contractYear emmean SE df lower.CL upper.CL
no 25.1 0.607 1129 23.9 26.3
yes 21.6 0.740 2021 20.2 23.1
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
mixedModelAge_receivingYards <- lmerTest::lmer(
receiving_yards ~ contractYear + ageCentered20 + ageCentered20Quadratic + years_of_experience + (1 + ageCentered20 | player_id),
data = player_statsContractsWRTE_seasonal,
control = lmerControl(optimizer = "bobyqa")
)
summary(mixedModelAge_receivingYards)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula:
receiving_yards ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 29952.6
Scaled residuals:
Min 1Q Median 3Q Max
-2.9222 -0.5213 -0.0916 0.4772 3.8044
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 532.259 23.071
ageCentered20 6.139 2.478 -0.70
Residual 137.910 11.744
Number of obs: 3558, groups: player_id, 1033
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 13.42269 1.57295 1376.84753 8.533 < 2e-16 ***
contractYearyes -2.83756 0.57200 2796.87598 -4.961 7.44e-07 ***
ageCentered20 2.11751 0.53966 2028.63105 3.924 9.01e-05 ***
ageCentered20Quadratic -0.43924 0.02844 1383.02319 -15.445 < 2e-16 ***
years_of_experience 3.96901 0.41384 1221.21592 9.591 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.121
ageCentrd20 -0.804 -0.149
agCntrd20Qd 0.696 0.079 -0.663
yrs_f_xprnc 0.211 0.021 -0.633 -0.082
R2m R2c
[1,] 0.1265075 0.7433555
contractYear emmean SE df lower.CL upper.CL
no 24.2 0.633 1134 23.0 25.5
yes 21.4 0.734 1855 19.9 22.8
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: receiving_epa ~ contractYear + (1 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 11672.6
Scaled residuals:
Min 1Q Median 3Q Max
-5.5671 -0.5715 -0.0364 0.5264 3.8987
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 0.5536 0.7441
Residual 1.3060 1.1428
Number of obs: 3490, groups: player_id, 1018
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 0.65163 0.03448 1371.93211 18.901 < 2e-16 ***
contractYearyes -0.14793 0.04753 3317.24675 -3.112 0.00187 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.356
R2m R2c
[1,] 0.00238466 0.299384
contractYear emmean SE df lower.CL upper.CL
no 0.652 0.0345 1199 0.584 0.719
yes 0.504 0.0478 2355 0.410 0.597
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula:
receiving_epa ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 11650.5
Scaled residuals:
Min 1Q Median 3Q Max
-5.4465 -0.5584 -0.0289 0.5261 3.8701
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 0.873149 0.9344
ageCentered20 0.005505 0.0742 -0.62
Residual 1.256079 1.1207
Number of obs: 3489, groups: player_id, 1017
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 3.152e-01 1.055e-01 1.022e+03 2.988 0.00287 **
contractYearyes -1.565e-01 4.996e-02 3.238e+03 -3.133 0.00174 **
ageCentered20 5.594e-02 3.443e-02 1.064e+03 1.625 0.10451
ageCentered20Quadratic -9.972e-03 1.967e-03 4.232e+02 -5.070 5.95e-07 ***
years_of_experience 9.926e-02 2.348e-02 1.052e+03 4.228 2.57e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.134
ageCentrd20 -0.836 -0.197
agCntrd20Qd 0.785 0.120 -0.754
yrs_f_xprnc 0.074 0.029 -0.486 -0.142
R2m R2c
[1,] 0.01823977 0.334487
contractYear emmean SE df lower.CL upper.CL
no 0.656 0.0354 1133 0.587 0.726
yes 0.500 0.0486 2385 0.404 0.595
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: fantasyPoints ~ contractYear + (1 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 36611.5
Scaled residuals:
Min 1Q Median 3Q Max
-3.2907 -0.5245 -0.1494 0.4380 4.6460
Random effects:
Groups Name Variance Std.Dev.
player_id (Intercept) 1247 35.31
Residual 1140 33.77
Number of obs: 3560, groups: player_id, 1034
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 49.380 1.342 1291.947 36.81 < 2e-16 ***
contractYearyes -8.623 1.444 3112.753 -5.97 2.64e-09 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
contrctYrys -0.263
R2m R2c
[1,] 0.006276973 0.5253879
contractYear emmean SE df lower.CL upper.CL
no 49.4 1.34 1151 46.7 52.0
yes 40.8 1.69 2167 37.4 44.1
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
Code
mixedModelAge_fantasyPtsReceiving <- lmerTest::lmer(
fantasyPoints ~ contractYear + ageCentered20 + ageCentered20Quadratic + years_of_experience + (1 + ageCentered20 | player_id),
data = player_statsContractsWRTE_seasonal,
control = lmerControl(optimizer = "bobyqa")
)
summary(mixedModelAge_fantasyPtsReceiving)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula:
fantasyPoints ~ contractYear + ageCentered20 + ageCentered20Quadratic +
years_of_experience + (1 + ageCentered20 | player_id)
Data: player_statsContractsWRTE_seasonal
Control: lmerControl(optimizer = "bobyqa")
REML criterion at convergence: 36247
Scaled residuals:
Min 1Q Median 3Q Max
-3.1178 -0.4991 -0.1295 0.4295 4.9895
Random effects:
Groups Name Variance Std.Dev. Corr
player_id (Intercept) 2501.70 50.017
ageCentered20 26.88 5.185 -0.72
Residual 904.91 30.082
Number of obs: 3558, groups: player_id, 1033
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 27.43781 3.69149 1339.44865 7.433 1.89e-13 ***
contractYearyes -6.37326 1.43120 2951.87067 -4.453 8.78e-06 ***
ageCentered20 3.29076 1.24364 1919.16753 2.646 0.00821 **
ageCentered20Quadratic -0.88027 0.06781 1135.74348 -12.981 < 2e-16 ***
years_of_experience 8.87280 0.91446 1172.95041 9.703 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cntrcY agCn20 agC20Q
contrctYrys 0.127
ageCentrd20 -0.817 -0.163
agCntrd20Qd 0.722 0.091 -0.697
yrs_f_xprnc 0.178 0.024 -0.592 -0.091
R2m R2c
[1,] 0.1150593 0.6622461
contractYear emmean SE df lower.CL upper.CL
no 47.5 1.39 1137 44.7 50.2
yes 41.1 1.68 2040 37.8 44.4
Degrees-of-freedom method: kenward-roger
Confidence level used: 0.95
18.2.4 QB/RB/WR/TE
18.3 Conclusion
18.4 Session Info
R version 4.4.2 (2024-10-31)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.1 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
locale:
[1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
[4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
time zone: UTC
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] lubridate_1.9.4 forcats_1.0.0 stringr_1.5.1 dplyr_1.1.4
[5] purrr_1.0.2 readr_2.1.5 tidyr_1.3.1 tibble_3.2.1
[9] ggplot2_3.5.1 tidyverse_2.0.0 emmeans_1.10.6 MuMIn_1.48.4
[13] lmerTest_3.1-3 lme4_1.1-35.5 Matrix_1.7-1 nflreadr_1.4.1
[17] petersenlab_1.1.0
loaded via a namespace (and not attached):
[1] tidyselect_1.2.1 psych_2.4.12 viridisLite_0.4.2
[4] fastmap_1.2.0 digest_0.6.37 rpart_4.1.23
[7] timechange_0.3.0 estimability_1.5.1 lifecycle_1.0.4
[10] cluster_2.1.6 magrittr_2.0.3 compiler_4.4.2
[13] rlang_1.1.4 Hmisc_5.2-1 tools_4.4.2
[16] yaml_2.3.10 data.table_1.16.4 knitr_1.49
[19] htmlwidgets_1.6.4 mnormt_2.1.1 plyr_1.8.9
[22] RColorBrewer_1.1-3 foreign_0.8-87 withr_3.0.2
[25] numDeriv_2016.8-1.1 nnet_7.3-19 grid_4.4.2
[28] stats4_4.4.2 lavaan_0.6-19 xtable_1.8-4
[31] colorspace_2.1-1 scales_1.3.0 MASS_7.3-61
[34] cli_3.6.3 mvtnorm_1.3-2 rmarkdown_2.29
[37] generics_0.1.3 rstudioapi_0.17.1 tzdb_0.4.0
[40] reshape2_1.4.4 minqa_1.2.8 DBI_1.2.3
[43] cachem_1.1.0 splines_4.4.2 parallel_4.4.2
[46] base64enc_0.1-3 mitools_2.4 vctrs_0.6.5
[49] boot_1.3-31 jsonlite_1.8.9 hms_1.1.3
[52] pbkrtest_0.5.3 Formula_1.2-5 htmlTable_2.4.3
[55] glue_1.8.0 nloptr_2.1.1 stringi_1.8.4
[58] gtable_0.3.6 quadprog_1.5-8 munsell_0.5.1
[61] pillar_1.10.0 htmltools_0.5.8.1 R6_2.5.1
[64] mix_1.0-13 evaluate_1.0.1 pbivnorm_0.6.0
[67] lattice_0.22-6 backports_1.5.0 broom_1.0.7
[70] memoise_2.0.1 Rcpp_1.0.13-1 coda_0.19-4.1
[73] gridExtra_2.3 nlme_3.1-166 checkmate_2.3.2
[76] xfun_0.49 pkgconfig_2.0.3