The statistical model:

\(y_t = \beta_0 + \beta_1 * (Elevation_s)_t + \beta_2 * Slope_t + (b_s)_t + \epsilon_t\)

Where:

Let’s define the parameters:

nstand = 5
nplot = 4
b0 = -1
b1 = .005
b2 = .1
sds = 2
sd = 1

Simulate other variables:

set.seed(16)
stand = rep(LETTERS[1:nstand], each = nplot)
standeff = rep( rnorm(nstand, 0, sds), each = nplot)
ploteff = rnorm(nstand*nplot, 0, sd)

Simulate elevation and slope:

elevation = rep( runif(nstand, 1000, 1500), each = nplot)
slope = runif(nstand*nplot, 2, 75)

Simulate response variable:

resp2 = b0 + b1*elevation + b2*slope + standeff + ploteff 

Your tasks (complete each task in its’ own code chunk, make sure to use echo=TRUE so I can see your code):

  1. Fit a linear mixed model with the response variable as a function of elevation and slope with stand as a random effect. Are the estimated parameters similar to the intial parameters as we defined them?
library(lme4)
## Warning: package 'lme4' was built under R version 3.6.1
## Loading required package: Matrix
library(lmerTest)
## Warning: package 'lmerTest' was built under R version 3.6.1
## 
## Attaching package: 'lmerTest'
## The following object is masked from 'package:lme4':
## 
##     lmer
## The following object is masked from 'package:stats':
## 
##     step
fit_model <- lmer(resp2 ~ 1 + elevation + slope + (1|stand))
summary(fit_model)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: resp2 ~ 1 + elevation + slope + (1 | stand)
## 
## REML criterion at convergence: 82
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -1.65583 -0.62467 -0.01693  0.53669  1.41736 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  stand    (Intercept) 1.208    1.099   
##  Residual             1.358    1.165   
## Number of obs: 20, groups:  stand, 5
## 
## Fixed effects:
##               Estimate Std. Error         df t value Pr(>|t|)    
## (Intercept) -21.314628   6.602053   3.001313  -3.228   0.0482 *  
## elevation     0.020600   0.004916   3.113482   4.190   0.0230 *  
## slope         0.095105   0.016441  15.868032   5.785 2.88e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##           (Intr) elevtn
## elevation -0.991       
## slope      0.049 -0.148
cat("b0 = ", b0, sep = "")
## b0 = -1
cat("b1 = ", b1, sep = "")
## b1 = 0.005
cat("b2 = ", b2, sep = "")
## b2 = 0.1

Defined intercept(b0) is -1 (Completely different compared to estimated intercept -21.314628) Defined Elevation(b1) is 0.005 (smaller compared to estimated elevation 0.020600) Defined slope(b1) is 0.1 (very close to estimated slope of 0.095105)

  1. Create a function for your model and run 1000 simulations of that model.
simulation_m <- function(nstand = 5, nplot = 4, b0 = -1, b1 = 0.005, b2 = 0.1, sds = 2, sd = 1) {
  stand <- rep(LETTERS[1:nstand], each = nplot)
  standeff <- rep(rnorm(nstand, 0, sds), each = nplot)
  ploteff <- rnorm(nstand * nplot, 0, sd)
  elevation <- rep(runif(nstand, 1000, 1500), each = nplot)
  slope <- runif(nstand * nplot, 2, 75)
  resp2 <- b0 + b1 * elevation + b2 * slope + standeff + ploteff
  
  data_f <- data.frame(resp2, elevation, slope, stand)
  lmer(resp2 ~ 1 + elevation + slope + (1|stand), data = data_f)
}
simulation_m()
## Linear mixed model fit by REML ['lmerModLmerTest']
## Formula: resp2 ~ 1 + elevation + slope + (1 | stand)
##    Data: data_f
## REML criterion at convergence: 80.9781
## Random effects:
##  Groups   Name        Std.Dev.
##  stand    (Intercept) 2.3573  
##  Residual             0.9754  
## Number of obs: 20, groups:  stand, 5
## Fixed Effects:
## (Intercept)    elevation        slope  
##   10.584601    -0.005464     0.086839
simulation_result <- replicate(n = 1000, expr = simulation_m())
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00350336
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.0045514
## (tol = 0.002, component 1)
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00363544
## (tol = 0.002, component 1)
## boundary (singular) fit: see ?isSingular
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00439561
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00239513
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00219495
## (tol = 0.002, component 1)
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00322495
## (tol = 0.002, component 1)
## boundary (singular) fit: see ?isSingular
length(simulation_result)
## [1] 1000
  1. Extract the stand and residual variances from this simulation run. Print the first 6 rows of the data.
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 3.6.1
## -- Attaching packages ---------------------------------------- tidyverse 1.2.1 --
## v ggplot2 3.2.1     v purrr   0.3.2
## v tibble  2.1.3     v dplyr   0.8.3
## v tidyr   0.8.3     v stringr 1.4.0
## v readr   1.3.1     v forcats 0.4.0
## Warning: package 'ggplot2' was built under R version 3.6.1
## Warning: package 'tidyr' was built under R version 3.6.1
## Warning: package 'readr' was built under R version 3.6.1
## Warning: package 'purrr' was built under R version 3.6.1
## Warning: package 'dplyr' was built under R version 3.6.1
## Warning: package 'stringr' was built under R version 3.6.1
## Warning: package 'forcats' was built under R version 3.6.1
## -- Conflicts ------------------------------------------- tidyverse_conflicts() --
## x tidyr::expand() masks Matrix::expand()
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(broom)
## Warning: package 'broom' was built under R version 3.6.1
library(broom.mixed)
## Warning: package 'broom.mixed' was built under R version 3.6.1
## Registered S3 methods overwritten by 'broom.mixed':
##   method         from 
##   augment.lme    broom
##   augment.merMod broom
##   glance.lme     broom
##   glance.merMod  broom
##   glance.stanreg broom
##   tidy.brmsfit   broom
##   tidy.gamlss    broom
##   tidy.lme       broom
##   tidy.merMod    broom
##   tidy.rjags     broom
##   tidy.stanfit   broom
##   tidy.stanreg   broom
## 
## Attaching package: 'broom.mixed'
## The following object is masked from 'package:broom':
## 
##     tidyMCMC
variances <- simulation_result %>% map_dfr(tidy, effects = "ran_pars", scales = "vcov")
head(variances,6)
## # A tibble: 6 x 4
##   effect   group    term             estimate
##   <chr>    <chr>    <chr>               <dbl>
## 1 ran_pars stand    var__(Intercept)    2.61 
## 2 ran_pars Residual var__Observation    1.11 
## 3 ran_pars stand    var__(Intercept)    9.73 
## 4 ran_pars Residual var__Observation    1.36 
## 5 ran_pars stand    var__(Intercept)    0.827
## 6 ran_pars Residual var__Observation    0.914
  1. Choose three different sample sizes (your choice) and run 1000 model simulations with each sample size. Create 3 visualizations that compare distributions of the variances for each of the 3 sample sizes. Make sure that the axes are labelled correctly. What do these graphs say about the relationship between sample size and variance?
library(ggplot2)
library(furrr)
## Warning: package 'furrr' was built under R version 3.6.1
## Loading required package: future
## Warning: package 'future' was built under R version 3.6.1
plan(multiprocess)
simulation_l_3 <- c(20, 60, 150) %>% 
  set_names(c("size_20", "size_60", "size_150")) %>% 
  map(function(.size) replicate(n = 1000, expr = simulation_m(nstand = .size)))
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.0023312
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.0149742
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00215173
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00201316
## (tol = 0.002, component 1)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00201341
## (tol = 0.002, component 1)
simulation_df <- simulation_l_3 %>% 
  modify_depth(.depth = 2, function(x) tidy(x, effects = "ran_pars", scales = "vcov")) %>% 
  map_dfr(bind_rows, .id = "id") %>% 
  filter(group == "stand")

simulation_df
## # A tibble: 3,000 x 5
##    id      effect   group term             estimate
##    <chr>   <chr>    <chr> <chr>               <dbl>
##  1 size_20 ran_pars stand var__(Intercept)     3.41
##  2 size_20 ran_pars stand var__(Intercept)     3.52
##  3 size_20 ran_pars stand var__(Intercept)     2.67
##  4 size_20 ran_pars stand var__(Intercept)     3.54
##  5 size_20 ran_pars stand var__(Intercept)     3.36
##  6 size_20 ran_pars stand var__(Intercept)     2.87
##  7 size_20 ran_pars stand var__(Intercept)     5.45
##  8 size_20 ran_pars stand var__(Intercept)     3.91
##  9 size_20 ran_pars stand var__(Intercept)     3.52
## 10 size_20 ran_pars stand var__(Intercept)     2.31
## # ... with 2,990 more rows
simulation_df %>% 
  mutate(
    id = case_when(
      id == "size_20" ~ "size = 20",
      id == "size_60" ~ "size = 60",
      id == "size_150" ~ "size = 150"
    )
  ) %>% 
  ggplot(aes(x = estimate) ) +
  geom_density(fill = "green", alpha = .25) +
  facet_wrap(~ id) +
  geom_vline(xintercept = 4) +
  theme_bw()

The plot shows that the estimate is more accurate when the sample size surges.

  1. Plot the coefficients of the estimates of elevation and slope. Hint: the x-axis should have 1000 values. Discuss the graphs.
library(furrr)
library(magrittr) 
## 
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
## 
##     set_names
## The following object is masked from 'package:tidyr':
## 
##     extract
library(dplyr)    
library(broom)
library(broom.mixed)
library(ggplot2)
simulation_es <- simulation_result %>% 
  map(tidy, effects = "fixed") %>% 
  bind_rows()
simulation_es
## # A tibble: 3,000 x 7
##    effect term        estimate std.error statistic    df     p.value
##    <chr>  <chr>          <dbl>     <dbl>     <dbl> <dbl>       <dbl>
##  1 fixed  (Intercept) -15.9      5.63       -2.83   2.99 0.0661     
##  2 fixed  elevation     0.0152   0.00426     3.57   2.99 0.0377     
##  3 fixed  slope         0.121    0.0157      7.73  15.5  0.00000107 
##  4 fixed  (Intercept) -13.9     13.3        -1.05   3.00 0.372      
##  5 fixed  elevation     0.0156   0.0117      1.33   2.99 0.276      
##  6 fixed  slope         0.124    0.0166      7.48  14.3  0.00000257 
##  7 fixed  (Intercept) -12.3      4.45       -2.75   2.92 0.0729     
##  8 fixed  elevation     0.0130   0.00336     3.87   3.01 0.0304     
##  9 fixed  slope         0.0937   0.0100      9.32  14.7  0.000000151
## 10 fixed  (Intercept) -11.9     21.4        -0.556  3.06 0.616      
## # ... with 2,990 more rows
simulation_es %>% 
  dplyr::filter(term %in% c("elevation", "slope")) %>% 
  group_by(term) %>% 
  mutate(x = 1:1000) %>%
  ungroup() %>% 
  mutate(real_value = ifelse(term == "elevation", 0.005, 0.1)) %>% 
  ggplot(aes(x = x, y = estimate)) +
  geom_line() +
  facet_wrap(~ term) +
  geom_hline(aes(yintercept = real_value, color = term), linetype = 2, size = 0.8) +
  theme_bw()

It shows estimates of elevation and slope are move in a wave-like pattern.

  1. Submit a link to this document in R Pubs to your Moodle. This assignment is worth 25 points.