{"id":3286,"date":"2023-11-06T04:45:53","date_gmt":"2023-11-06T04:45:53","guid":{"rendered":"http:\/\/optimumsportsperformance.com\/blog\/?p=3286"},"modified":"2023-11-06T13:04:01","modified_gmt":"2023-11-06T13:04:01","slug":"simulations-in-r-part-8-simulating-mixed-models","status":"publish","type":"post","link":"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-8-simulating-mixed-models\/","title":{"rendered":"Simulations in R Part 8 &#8211; Simulating Mixed Models"},"content":{"rendered":"<p>We&#8217;ve built up a number of simulations over the 7 articles in this series. The last few articles have been looking at linear regression and simulating different intricacies in the data that allow us to explore model assumptions. To end this series, we will now extend the linear model to a mixed model. We will start by building a linear regression model and go through the steps of simulation to build up the hierarchical structure of the data.<\/p>\n<p>For those interesting here are the previous 7 articles in this series:<\/p>\n<ul>\n<li><strong><a href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-1-functions-for-simulation-resampling\/\"><span style=\"color: #0000ff;\">Part 1<\/span><\/a><\/strong> discussed the basic functions for simulating and sampling data in R<\/li>\n<li><span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-2-bootstrapping-simulating-bivariate-and-multivariate-distributions\/\">Part 2<\/a><\/strong> <\/span>walked us through how to perform bootstrap resampling and then simulate bivariate and multivariate distributions<\/li>\n<li><span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-3-group-comparisons-via-simulation-simulating-t-tests\/\">Part 3<\/a><\/strong><\/span> we worked making group comparisons by simulating thousands of t-tests<\/li>\n<li><span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-4-simulating-regression-models\/\">Part 4<\/a><\/strong><\/span> building simulations for linear regression<\/li>\n<li><span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-5-homoskedasticity-assumption-in-regression\/\">Part 5<\/a><\/strong><\/span> using simulation to investigate the homoskedasticity assumption in regression<\/li>\n<li><span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/simulations-in-r-part-6-multicollinearity-assumption-in-regression\/\">Part 6<\/a><\/strong> <\/span>using simulation to investigate the multicollinearity assumption in regression<\/li>\n<li><strong><span style=\"color: #0000ff;\">Part 7<\/span><\/strong> simulating measurement error in regression<\/li>\n<\/ul>\n<p>As always, complete code for this article is available on my <strong><a href=\"https:\/\/github.com\/pw2\/Constructing-Simulations-Tutorial\"><span style=\"color: #0000ff;\">GitHub page<\/span><\/a><\/strong>.<\/p>\n<p><strong><em>Side Note: <\/em><\/strong>This is a very code heavy article as the goal is to show not only simulations of data and models but how to extract the model parameters from the list of simulations. As such, this a rather long article with minimal interpretation of the models.<\/p>\n<p><span style=\"text-decoration: underline;\"><strong>First a linear model<\/strong><\/span><\/p>\n<p>Our data will look at training load for 10 players in two different positions, Forwards (F) and Mids (M). The Forwards will be simulated to have less training load than the Mids and we will add some random error around the difference in these group means. We will simulate this as a linaer model where b0 represents the model intercept and is the mean value for Forwards and b1 represents the coefficient for when the group is Mids.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nlibrary(tidyverse)\r\nlibrary(broom)\r\nlibrary(lme4)\r\n\r\ntheme_set(theme_light())\r\n## Model Parameters\r\nn_positions &lt;- 2\r\nn_players &lt;- 10\r\nb0 &lt;- 80\r\nb1 &lt;- 20\r\nsigma &lt;- 10\r\n\r\n## Simulate\r\nset.seed(300)\r\npos &lt;- rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players)\r\nplayer_id &lt;- rep(1:10, times = 2)\r\nmodel_error &lt;- rnorm(n = n_positions*n_players, mean = 0, sd = sigma)\r\ntraining_load &lt;- b0 + b1 * (pos == &quot;M&quot;) + model_error\r\n\r\nd &lt;- data.frame(pos, player_id, training_load)\r\nd<\/pre>\n<p>Calculate some summary statistics<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nd %&gt;%\r\n  ggplot(aes(x = pos, y = training_load)) +\r\n  geom_boxplot()\r\n\r\nd %&gt;%\r\n  group_by(pos) %&gt;%\r\n  summarize(N = n(),\r\n            avg = mean(training_load),\r\n            sd = sd(training_load)) %&gt;%\r\n  mutate(se = sd \/ sqrt(N)) %&gt;%\r\n  knitr::kable()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3287\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM-975x1024.png\" alt=\"\" width=\"444\" height=\"466\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM-975x1024.png 975w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM-286x300.png 286w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM-768x807.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM-624x656.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.32\u202fPM.png 1146w\" sizes=\"auto, (max-width: 444px) 100vw, 444px\" \/><\/a> <a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.37\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3288\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.37\u202fPM.png\" alt=\"\" width=\"427\" height=\"115\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.37\u202fPM.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.40.37\u202fPM-300x81.png 300w\" sizes=\"auto, (max-width: 427px) 100vw, 427px\" \/><\/a><\/p>\n<p>Build a linear model<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nfit &lt;- lm(training_load ~ pos, data = d)\r\nsummary(fit)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3289\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM.png\" alt=\"\" width=\"427\" height=\"324\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM.png 900w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM-300x227.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM-768x582.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.42.04\u202fPM-624x473.png 624w\" sizes=\"auto, (max-width: 427px) 100vw, 427px\" \/><\/a><\/p>\n<p>Now, we wrap all the steps in a function so that we can use <strong>replicate()<\/strong> to create thousands of simulations or to change parameters of our simulation. The end result of the function is going to be the linear regression model.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nsim_func &lt;- function(n_positions = 2, n_players = 10, b0 = 80, b1 = 20, sigma = 10){\r\n\r\n  ## simulate data\r\n  pos &lt;- rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players)\r\n  player_id &lt;- rep(1:10, times = 2)\r\n  model_error &lt;- rnorm(n = n_positions*n_players, mean = 0, sd = sigma)\r\n  training_load &lt;- b0 + b1 * (pos == &quot;M&quot;) + model_error\r\n\r\n  ## store in data frame\r\n  d &lt;- data.frame(pos, player_id, training_load)\r\n  \r\n  ## construct linear model\r\n  fit &lt;- lm(training_load ~ pos, data = d)\r\n  summary(fit)\r\n}\r\n<\/pre>\n<p>Try the function out with the default parameters<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nsim_func()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3290\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM.png\" alt=\"\" width=\"495\" height=\"358\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM.png 924w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM-300x217.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM-768x555.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.44.38\u202fPM-624x451.png 624w\" sizes=\"auto, (max-width: 495px) 100vw, 495px\" \/><\/a><\/p>\n<p>Use <strong>replicate()<\/strong> to create many simulations.<\/p>\n<p>Doing this simulation once doesn&#8217;t help us. We want to be able to do this thousands of times. All of the articles in this series have used <strong>for()<\/strong> loops up until this point. But, if you recall the first article in the series where I laid out several helpful functions for coding simulations, I showed an example of the <strong>replicate()<\/strong> function, which will take a function and run it&#8217;s result for as many times as you specify. I found this function while I was working through the simulation chapter of <strong><span style=\"color: #0000ff;\"><a style=\"color: #0000ff;\" href=\"https:\/\/www.amazon.com\/Regression-Stories-Analytical-Methods-Research\/dp\/110702398X\">Gelman et al&#8217;s book, Regression and Other Stories<\/a><\/span><\/strong>. I think in cases like a mixed model simulation, where you can have many layers and complexities to the data, writing a simple function and then replicating it thousands of times is much easier to debug and much cleaner for others to read than having a bunch of nested <strong>for()<\/strong> loops.<\/p>\n<p><em><strong>Technical Note:<\/strong><\/em> We specify the argument <strong>simplify = FALSE<\/strong> so that the results are returned in a list format. This makes more sense since the results are the regression summary results and not a data frame.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nteam_training &lt;- replicate(n = 1000,\r\n                  sim_func(),\r\n                  simplify = FALSE)\r\n<\/pre>\n<p>Coefficient Results<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nteam_training %&gt;%\r\n  map_df(tidy) %&gt;%\r\n  select(term, estimate) %&gt;%\r\n  ggplot(aes(x = estimate, fill = term)) +\r\n  geom_density() +\r\n  facet_wrap(~term, scales = &quot;free_x&quot;)\r\n\r\nteam_training %&gt;%\r\n  map_df(tidy) %&gt;%\r\n  select(term, estimate) %&gt;%\r\n  group_by(term) %&gt;%\r\n  summarize(avg = mean(estimate),\r\n            SD = sd(estimate))\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.48.50\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3291\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.48.50\u202fPM.png\" alt=\"\" width=\"290\" height=\"131\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.48.50\u202fPM.png 394w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.48.50\u202fPM-300x136.png 300w\" sizes=\"auto, (max-width: 290px) 100vw, 290px\" \/><\/a> <a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3292\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM-975x1024.png\" alt=\"\" width=\"430\" height=\"451\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM-975x1024.png 975w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM-286x300.png 286w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM-768x807.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM-624x656.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.02\u202fPM.png 1142w\" sizes=\"auto, (max-width: 430px) 100vw, 430px\" \/><\/a><\/p>\n<p>Compare the simulated results to the results of the original model fit.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\ntidy(fit)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3293\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM.png\" alt=\"\" width=\"493\" height=\"131\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM.png 804w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM-300x80.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM-768x204.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.49.48\u202fPM-624x166.png 624w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><\/a><\/p>\n<p>Model fit parameters<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nteam_training %&gt;%\r\n  map_df(glance) %&gt;%\r\n  select(adj.r.squared, sigma) %&gt;%\r\n  summarize(across(.cols = everything(),\r\n                   ~mean(.x)))\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.51.54\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3294\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.51.54\u202fPM.png\" alt=\"\" width=\"233\" height=\"89\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.51.54\u202fPM.png 372w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.51.54\u202fPM-300x115.png 300w\" sizes=\"auto, (max-width: 233px) 100vw, 233px\" \/><\/a><br \/>\nCompare these results to the original fit<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nfit %&gt;% \r\n  glance()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3295\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM-1024x139.png\" alt=\"\" width=\"625\" height=\"85\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM-1024x139.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM-300x41.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM-768x104.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM-624x84.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-7.52.36\u202fPM.png 1522w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Mixed Model 1<\/strong><\/span><\/p>\n<p>Now that we have the general frame work for building a simulation function and using <strong>replicate()<\/strong> we will to build a mixed model simulation.<\/p>\n<p>Above we had a team with two positions groups and individual players nested within those position groups. In this mixed model, we will add a second team so that we can explore hierarchical data.<\/p>\n<p>We will simulate data from 3 teams, each with 2 positions (Forward &amp; Mid). This is a pretty simple mixed model. We will build a more complex one after we get a handle on the code below.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Model Parameters\r\nn_teams &lt;- 3\r\nn_positions &lt;- 2\r\nn_players &lt;- 10\r\n\r\nteam1_fwd_avg &lt;- 130\r\nteam1_fwd_sd &lt;- 15\r\nteam1_mid_avg &lt;- 100\r\nteam1_mid_sd &lt;- 5\r\n\r\nteam2_fwd_avg &lt;- 150\r\nteam2_fwd_sd &lt;- 20\r\nteam2_mid_avg &lt;- 90\r\nteam2_mid_sd &lt;- 10\r\n\r\nteam3_fwd_avg &lt;- 180\r\nteam3_fwd_sd &lt;- 15\r\nteam3_mid_avg &lt;- 150\r\nteam3_mid_sd &lt;- 15\r\n\r\n\r\n## Simulated data frame\r\nteam &lt;- rep(c(&quot;Team1&quot;,&quot;Team2&quot;, &quot;Team3&quot;), each = n_players * n_positions)\r\npos &lt;- c(rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players), rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players), rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players))\r\nplayer_id &lt;- as.factor(round(seq(from = 100, to = 300, length = length(team)), 0))\r\n\r\nd &lt;- data.frame(team, pos, player_id) d %&gt;%\r\n  head()\r\n\r\n# simulate training loads\r\nset.seed(555)\r\ntraining_load &lt;- c(rnorm(n = n_players, mean = team1_mid_avg, sd = team1_mid_sd), rnorm(n = n_players, mean = team1_fwd_avg, sd = team1_fwd_sd), rnorm(n = n_players, mean = team2_mid_avg, sd = team2_mid_sd), rnorm(n = n_players, mean = team2_fwd_avg, sd = team2_fwd_sd), rnorm(n = n_players, mean = team3_mid_avg, sd = team3_mid_sd), rnorm(n = n_players, mean = team3_fwd_avg, sd = team3_fwd_sd)) d ,- d %&gt;%\r\n  bind_cols(training_load = training_load) \r\n\r\nd %&gt;%\r\n  head()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.04.17\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3301\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.04.17\u202fPM.png\" alt=\"\" width=\"398\" height=\"232\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.04.17\u202fPM.png 552w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.04.17\u202fPM-300x175.png 300w\" sizes=\"auto, (max-width: 398px) 100vw, 398px\" \/><\/a><br \/>\nCalculate summary statistics<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Average training load by team\r\nd %&gt;%\r\n  group_by(team) %&gt;%\r\n  summarize(avg = mean(training_load),\r\n            SD = sd(training_load))\r\n\r\n## Average training load by pos\r\nd %&gt;%\r\n  group_by(pos) %&gt;%\r\n  summarize(avg = mean(training_load),\r\n            SD = sd(training_load))\r\n\r\n## Average training load by team &amp; position\r\nd %&gt;%\r\n  group_by(team, pos) %&gt;%\r\n  summarize(avg = mean(training_load),\r\n            SD = sd(training_load)) %&gt;%\r\n  arrange(pos)\r\n\r\n## Plot\r\nd %&gt;%\r\n  ggplot(aes(x = training_load, fill = team)) +\r\n  geom_density(alpha = 0.5) +\r\n  facet_wrap(~pos)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3302\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM-975x1024.png\" alt=\"\" width=\"466\" height=\"489\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM-975x1024.png 975w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM-286x300.png 286w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM-768x807.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM-624x656.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.15\u202fPM.png 1142w\" sizes=\"auto, (max-width: 466px) 100vw, 466px\" \/><\/a> <a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.25\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3303\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.25\u202fPM.png\" alt=\"\" width=\"290\" height=\"236\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.25\u202fPM.png 386w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.05.25\u202fPM-300x244.png 300w\" sizes=\"auto, (max-width: 290px) 100vw, 290px\" \/><\/a><\/p>\n<p>Construct the mixed model and evaluate the outputs<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Mixed Model\r\nfit_lmer &lt;- lmer(training_load ~ pos + (1 |team), data = d)\r\nsummary(fit_lmer)\r\ncoef(fit_lmer)\r\nfixef(fit_lmer)\r\nranef(fit_lmer)\r\nsigma(fit_lmer)\r\nhist(residuals(fit_lmer))\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3304\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM-1024x947.png\" alt=\"\" width=\"625\" height=\"578\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM-1024x947.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM-300x277.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM-768x710.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM-624x577.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.09.06\u202fPM.png 1376w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p>Write a mixed model function<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nsim_func_lmer &lt;- function(n_teams = 3, \r\n                          n_positions = 2, \r\n                          n_players = 10, \r\n                          team1_fwd_avg = 130,\r\n                          team1_fwd_sd = 15,\r\n                          team1_mid_avg = 100,\r\n                          team1_mid_sd = 5,\r\n                          team2_fwd_avg = 150,\r\n                          team2_fwd_sd = 20,\r\n                          team2_mid_avg = 90,\r\n                          team2_mid_sd = 10,\r\n                          team3_fwd_avg = 180,\r\n                          team3_fwd_sd = 15,\r\n                          team3_mid_avg = 150,\r\n                          team3_mid_sd = 15){\r\n\r\n        ## Simulated data frame\r\n        team &lt;- rep(c(&quot;Team1&quot;,&quot;Team2&quot;, &quot;Team3&quot;), each = n_players * n_positions)\r\n        pos &lt;- c(rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players), rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players), rep(c(&quot;M&quot;, &quot;F&quot;), each = n_players))\r\n        player_id &lt;- as.factor(round(seq(from = 100, to = 300, length = length(team)), 0))\r\n        \r\n        d &lt;- data.frame(team, pos, player_id)\r\n\r\n        # simulate training loads\r\n        training_load &lt;- c(rnorm(n = n_players, mean = team1_mid_avg, sd = team1_mid_sd),\r\n                   rnorm(n = n_players, mean = team1_fwd_avg, sd = team1_fwd_sd),\r\n                   rnorm(n = n_players, mean = team2_mid_avg, sd = team2_mid_sd),\r\n                   rnorm(n = n_players, mean = team2_fwd_avg, sd = team2_fwd_sd),\r\n                   rnorm(n = n_players, mean = team3_mid_avg, sd = team3_mid_sd),\r\n                   rnorm(n = n_players, mean = team3_fwd_avg, sd = team3_fwd_sd))\r\n  \r\n        ## construct the mixed model\r\n  fit_lmer &lt;- lmer(training_load ~ pos + (1 |team), data = d)\r\n  summary(fit_lmer)\r\n}\r\n<\/pre>\n<p>Try out the function<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nsim_func_lmer()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.10.40\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3305\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.10.40\u202fPM.png\" alt=\"\" width=\"431\" height=\"578\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.10.40\u202fPM.png 694w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.10.40\u202fPM-224x300.png 224w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.10.40\u202fPM-624x836.png 624w\" sizes=\"auto, (max-width: 431px) 100vw, 431px\" \/><\/a><\/p>\n<p>Now use <strong>replicate()<\/strong> and create 1000 simulations of the model and look at the first model in the list<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nteam_training_lmer &lt;- replicate(n = 1000,\r\n                  sim_func_lmer(),\r\n                  simplify = FALSE)\r\n\r\n## look at the first model in the list\r\nteam_training_lmer&#x5B;&#x5B;1]]$coefficient\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.13.01\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3306\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.13.01\u202fPM.png\" alt=\"\" width=\"493\" height=\"157\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.13.01\u202fPM.png 646w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.13.01\u202fPM-300x96.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.13.01\u202fPM-624x199.png 624w\" sizes=\"auto, (max-width: 493px) 100vw, 493px\" \/><\/a><\/p>\n<p>Store the coefficient results of the 1000 simulations in a data frame, create plots of the model coefficients, and compare the results of the simulation to the original mixed model.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n\r\nlmer_coef &lt;- matrix(NA, ncol = 5, nrow = length(team_training_lmer))\r\ncolnames(lmer_coef) &lt;- c(&quot;intercept&quot;, &quot;intercept_se&quot;, &quot;posM&quot;, &quot;posM_se&quot;, 'model_sigma')\r\n\r\nfor(i in 1:length(team_training_lmer)){\r\n  \r\n  lmer_coef&#x5B;i, 1] &lt;- team_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;1]\r\n  lmer_coef&#x5B;i, 2] &lt;- team_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;3]\r\n  lmer_coef&#x5B;i, 3] &lt;- team_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;2]\r\n  lmer_coef&#x5B;i, 4] &lt;- team_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;4]\r\n  lmer_coef&#x5B;i, 5] &lt;- team_training_lmer&#x5B;&#x5B;i]]$sigma\r\n  \r\n}\r\n\r\nlmer_coef &lt;- as.data.frame(lmer_coef) head(lmer_coef) ## Plot the coefficient for position lmer_coef %&gt;%\r\n  ggplot(aes(x = posM)) +\r\n  geom_density(fill = &quot;palegreen&quot;)\r\n\r\n## Summarize the coefficients and their standard errors for the simulations\r\nlmer_coef %&gt;% \r\n  summarize(across(.cols = everything(),\r\n                   ~mean(.x)))\r\n\r\n## compare to the original model\r\nbroom.mixed::tidy(fit_lmer)\r\nsigma(fit_lmer)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3307\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM-1024x541.png\" alt=\"\" width=\"625\" height=\"330\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM-1024x541.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM-300x158.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM-768x406.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.23.58\u202fPM-624x330.png 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p>Extract the random effects for the intercept and the residual for each of the simulated models<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nranef_sim &lt;- matrix(NA, ncol = 2, nrow = length(team_training_lmer))\r\ncolnames(ranef_sim) &lt;- c(&quot;intercept_sd&quot;, &quot;residual_sd&quot;)\r\n\r\nfor(i in 1:length(team_training_lmer)){\r\n  \r\n  ranef_sim&#x5B;i, 1] &lt;- team_training_lmer&#x5B;&#x5B;i]]$varcor %&gt;% as.data.frame() %&gt;% select(sdcor) %&gt;% slice(1) %&gt;% pull(sdcor)\r\n  ranef_sim&#x5B;i, 2] &lt;- team_training_lmer&#x5B;&#x5B;i]]$varcor %&gt;% as.data.frame() %&gt;% select(sdcor) %&gt;% slice(2) %&gt;% pull(sdcor)\r\n  \r\n}\r\n\r\nranef_sim &lt;- as.data.frame(ranef_sim) head(ranef_sim) ## Summarize the results ranef_sim %&gt;%\r\n  summarize(across(.cols = everything(),\r\n                   ~mean(.x)))\r\n\r\n## Compare with the original model\r\nVarCorr(fit_lmer)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.25.57\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3308\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.25.57\u202fPM.png\" alt=\"\" width=\"497\" height=\"570\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.25.57\u202fPM.png 628w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.25.57\u202fPM-262x300.png 262w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.25.57\u202fPM-624x715.png 624w\" sizes=\"auto, (max-width: 497px) 100vw, 497px\" \/><\/a><\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Mixed Model 2<\/strong><\/span><\/p>\n<p>Above was a pretty simple model, just to get our feet wet. Let&#8217;s create a more complicated model. Usually in sport and exercise science we have repeated measures of individuals. Often, researchers will set the individual players as random effects with the fixed effects being the component that the researcher is attempting to make an inference about.<\/p>\n<p>In this example, we will set up a team of 12 players with three positions (4 players per position): Forward, Mid, Defender. The aim is to explore the training load differences between position groups while accounting for repeated observations of individuals (in this case, each player will have 20 training sessions). Similar to our first regression model, we will build a data frame of everything we need and then calculate the outcome variable (training load) with a regression model using parameters that we specify. To make this work, we will need to specific an intercept and slope for the position group and an intercept and slope for the individual players as well as a model sigma value. Once we&#8217;ve done that, we will fit a mixed model, write a function, and then create 1000 simulations.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Set up the data frame\r\nn_pos &lt;- 3\r\nn_players &lt;- 12\r\nn_obs &lt;- 20\r\nplayers &lt;- as.factor(round(seq(from = 100, to = 300, length = n_players), 0))\r\n\r\n\r\ndat &lt;- data.frame( player_id = rep(players, each = n_obs), pos = rep(c(&quot;Fwd&quot;, &quot;Mid&quot;, &quot;Def&quot;), each = n_players\/n_pos * n_obs), training_day = rep(1:n_obs, times = n_players) ) dat %&gt;%\r\n  head()\r\n\r\n## Create model parameters\r\n# NOTE: Defender will be the intercept\r\nset.seed(6687)\r\npos_intercept &lt;- 150\r\nposF_coef &lt;- 170\r\nposM_coef &lt;- -70\r\nindividual_intercept &lt;- 50\r\nindividual_slope &lt;- 10\r\nsigma &lt;- 10\r\nmodel_error &lt;- rnorm(n = nrow(dat), mean = 0, sd = sigma)\r\n\r\n\r\n## we will also create some individual player variance\r\nindividual_player_variance &lt;- c()\r\n\r\nfor(i in players){\r\n\r\n  individual_player_variance&#x5B;i] &lt;- rnorm(n = 1, \r\n                  mean = runif(min = 2, max = 10, n = 1), \r\n                  sd = runif(min = 2, max = 5, n = 1))\r\n  \r\n}\r\n\r\nindividual_player_variance &lt;- rep(individual_player_variance, each = n_obs)\r\n\r\ndat$training_load &lt;- pos_intercept + posF_coef * (dat$pos == &quot;Fwd&quot;) + posM_coef * (dat$pos == &quot;Mid&quot;) + individual_intercept + individual_slope * individual_player_variance + model_error dat %&gt;%\r\n  head()\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.27.32\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3309\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.27.32\u202fPM.png\" alt=\"\" width=\"486\" height=\"230\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.27.32\u202fPM.png 658w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.27.32\u202fPM-300x142.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.27.32\u202fPM-624x296.png 624w\" sizes=\"auto, (max-width: 486px) 100vw, 486px\" \/><\/a><br \/>\nCalculate summary stats<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Average training load by pos\r\ndat %&gt;%\r\n  group_by(pos) %&gt;%\r\n  summarize(avg = mean(training_load),\r\n            SD = sd(training_load))\r\n\r\n## Plot\r\ndat %&gt;%\r\n  ggplot(aes(x = training_load, fill = pos)) +\r\n  geom_density(alpha = 0.5)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.36\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3310\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.36\u202fPM.png\" alt=\"\" width=\"416\" height=\"227\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.36\u202fPM.png 612w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.36\u202fPM-300x164.png 300w\" sizes=\"auto, (max-width: 416px) 100vw, 416px\" \/><\/a> <a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3311\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM-967x1024.png\" alt=\"\" width=\"469\" height=\"497\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM-967x1024.png 967w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM-283x300.png 283w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM-768x813.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM-624x660.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.28.50\u202fPM.png 1130w\" sizes=\"auto, (max-width: 469px) 100vw, 469px\" \/><\/a><\/p>\n<p>Construct the mixed model and evaluate the output<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n## Mixed Model\r\nfit_lmer_pos &lt;- lmer(training_load ~ pos + (1 | player_id), data = dat)\r\nsummary(fit_lmer_pos)\r\ncoef(fit_lmer_pos)\r\nfixef(fit_lmer_pos)\r\nranef(fit_lmer_pos)\r\nsigma(fit_lmer_pos)\r\nhist(residuals(fit_lmer_pos))\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3312\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM-1024x566.png\" alt=\"\" width=\"625\" height=\"345\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM-1024x566.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM-300x166.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM-768x425.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.32.39\u202fPM-624x345.png 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><br \/>\nCreate a function for the simulation<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nsim_func_lmer2 &lt;- function(n_pos = 3,\r\n                          n_players = 12,\r\n                          n_obs = 20,\r\n                          pos_intercept = 150,\r\n                          posF_coef = 170,\r\n                          posM_coef = -70,\r\n                          individual_intercept = 50,\r\n                          individual_slope = 10,\r\n                          sigma = 10){\r\n  \r\n  players &lt;- as.factor(round(seq(from = 100, to = 300, length = n_players), 0))\r\n\r\n  dat &lt;- data.frame(\r\n  player_id = rep(players, each = n_obs),\r\n  pos = rep(c(&quot;Fwd&quot;, &quot;Mid&quot;, &quot;Def&quot;), each = n_players\/n_pos * n_obs),\r\n  training_day = rep(1:n_obs, times = n_players)\r\n  )\r\n  \r\n  model_error &lt;- rnorm(n = nrow(dat), mean = 0, sd = sigma)\r\n  \r\n  individual_player_variance &lt;- c()\r\n\r\n  for(i in players){\r\n\r\n    individual_player_variance&#x5B;i] &lt;- rnorm(n = 1, \r\n                  mean = runif(min = 2, max = 10, n = 1), \r\n                  sd = runif(min = 2, max = 5, n = 1))\r\n    }\r\n\r\n  individual_player_variance &lt;- rep(individual_player_variance, each = n_obs)\r\n\r\n  dat$training_load &lt;- pos_intercept + posF_coef * (dat$pos == &quot;Fwd&quot;) + posM_coef * (dat$pos == &quot;Mid&quot;) + individual_intercept + individual_slope * individual_player_variance + model_error\r\n\r\n  fit_lmer_pos &lt;- lmer(training_load ~ pos + (1 | player_id), data = dat)\r\n  summary(fit_lmer_pos)\r\n}\r\n<\/pre>\n<p>Now use `replicate()` and create 1000 simulations of the model and look at the first model in the list.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nplayer_training_lmer &lt;- replicate(n = 1000,\r\n                  sim_func_lmer2(),\r\n                  simplify = FALSE)\r\n\r\n## look at the first model in the list\r\nplayer_training_lmer&#x5B;&#x5B;1]]$coefficient\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.35.56\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-3313\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.35.56\u202fPM.png\" alt=\"\" width=\"494\" height=\"147\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.35.56\u202fPM.png 646w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.35.56\u202fPM-300x89.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.35.56\u202fPM-624x185.png 624w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><\/a><\/p>\n<p>Store the coefficient results from the simulations, summarize them, and compare them to the original mixed model.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nlmer_player_coef &lt;- matrix(NA, ncol = 7, nrow = length(player_training_lmer))\r\ncolnames(lmer_player_coef) &lt;- c(&quot;intercept&quot;, &quot;intercept_se&quot;,&quot;posFwd&quot;, &quot;posFwd_se&quot;, &quot;posMid&quot;, &quot;posMid_se&quot;, 'model_sigma')\r\n\r\nfor(i in 1:length(player_training_lmer)){\r\n  \r\n  lmer_player_coef&#x5B;i, 1] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;1]\r\n  lmer_player_coef&#x5B;i, 2] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;4]\r\n  lmer_player_coef&#x5B;i, 3] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;2]\r\n  lmer_player_coef&#x5B;i, 4] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;5]\r\n  lmer_player_coef&#x5B;i, 5] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;3]\r\n  lmer_player_coef&#x5B;i, 6] &lt;- player_training_lmer&#x5B;&#x5B;i]]$coefficients&#x5B;6]\r\n  lmer_player_coef&#x5B;i, 7] &lt;- player_training_lmer&#x5B;&#x5B;i]]$sigma\r\n  \r\n}\r\n\r\nlmer_player_coef &lt;- as.data.frame(lmer_player_coef) head(lmer_player_coef) ## Plot the coefficient for position lmer_player_coef %&gt;%\r\n  ggplot(aes(x = posFwd)) +\r\n  geom_density(fill = &quot;palegreen&quot;)\r\n\r\nlmer_player_coef %&gt;%\r\n  ggplot(aes(x = posMid)) +\r\n  geom_density(fill = &quot;palegreen&quot;)\r\n\r\n\r\n## Summarize the coefficients and their standard errors for the simulations\r\nlmer_player_coef %&gt;% \r\n  summarize(across(.cols = everything(),\r\n                   ~mean(.x)))\r\n\r\n## compare to the original model\r\nbroom.mixed::tidy(fit_lmer_pos)\r\nsigma(fit_lmer_pos)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3314\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM-1024x476.png\" alt=\"\" width=\"625\" height=\"291\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM-1024x476.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM-300x140.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM-768x357.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.39.43\u202fPM-624x290.png 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><br \/>\nExtract the random effects for the intercept and the residual for each of the simulated models.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\nranef_sim_player &lt;- matrix(NA, ncol = 2, nrow = length(player_training_lmer))\r\ncolnames(ranef_sim_player) &lt;- c(&quot;player_sd&quot;, &quot;residual_sd&quot;)\r\n\r\nfor(i in 1:length(player_training_lmer)){\r\n  \r\n  ranef_sim_player&#x5B;i, 1] &lt;- player_training_lmer&#x5B;&#x5B;i]]$varcor %&gt;% as.data.frame() %&gt;% select(sdcor) %&gt;% slice(1) %&gt;% pull(sdcor)\r\n  ranef_sim_player&#x5B;i, 2] &lt;- player_training_lmer&#x5B;&#x5B;i]]$varcor %&gt;% as.data.frame() %&gt;% select(sdcor) %&gt;% slice(2) %&gt;% pull(sdcor)\r\n  \r\n}\r\n\r\nranef_sim_player &lt;- as.data.frame(ranef_sim_player) head(ranef_sim_player) ## Summarize the results ranef_sim_player %&gt;%\r\n  summarize(across(.cols = everything(),\r\n                   ~mean(.x)))\r\n\r\n## Compare with the original model\r\nVarCorr(fit_lmer_pos)\r\n<\/pre>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-3315\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM-1024x380.png\" alt=\"\" width=\"625\" height=\"232\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM-1024x380.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM-300x111.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM-768x285.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM-624x232.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2023\/11\/Screenshot-2023-11-05-at-8.42.08\u202fPM.png 1508w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Wrapping Up<\/strong><\/span><\/p>\n<p>Mixed models can get really complicated and have a lot of layers to them. For example, we could make this a multivariable model with independent variables that have some level of correlation with each other. We could also add some level of autocorrelation for each player&#8217;s observations. There are also a number of different ways that you can construct these types of simulations. The two approaches used here are just dipping their toes in. Perhaps in future articles I&#8217;ll put together code for more complex mixed models.<\/p>\n<p>All of the code for this article and the other 7 articles in this series are available on my <span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/github.com\/pw2\/Constructing-Simulations-Tutorial\">GitHub page<\/a><\/strong><\/span>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We&#8217;ve built up a number of simulations over the 7 articles in this series. The last few articles have been looking at linear regression and simulating different intricacies in the data that allow us to explore model assumptions. To end this series, we will now extend the linear model to a mixed model. We will [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[47],"tags":[],"class_list":["post-3286","post","type-post","status-publish","format-standard","hentry","category-model-building-in-r"],"_links":{"self":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/3286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/comments?post=3286"}],"version-history":[{"count":4,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/3286\/revisions"}],"predecessor-version":[{"id":3319,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/3286\/revisions\/3319"}],"wp:attachment":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/media?parent=3286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/categories?post=3286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/tags?post=3286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}