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):
library(lme4)
## Loading required package: Matrix
fit1 = lmer(resp2 ~ elevation + slope + (1|stand))
fit1
## Linear mixed model fit by REML ['lmerMod']
## Formula: resp2 ~ elevation + slope + (1 | stand)
## REML criterion at convergence: 81.9874
## Random effects:
## Groups Name Std.Dev.
## stand (Intercept) 1.099
## Residual 1.165
## Number of obs: 20, groups: stand, 5
## Fixed Effects:
## (Intercept) elevation slope
## -21.31463 0.02060 0.09511
summary(fit1)
## Linear mixed model fit by REML ['lmerMod']
## Formula: resp2 ~ 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 t value
## (Intercept) -21.314628 6.602053 -3.228
## elevation 0.020600 0.004916 4.190
## slope 0.095105 0.016441 5.785
##
## Correlation of Fixed Effects:
## (Intr) elevtn
## elevation -0.991
## slope 0.049 -0.148
Estimated β0 is -21.3146, which is far from the initial parameter -1. Estimated β1 is 0.0206, which is not close to initial parameter 0.005. Estimated β2 is 0.0951, which is much close to the initial parameter 0.1
library(purrr)
set.seed(18)
mixed_fun = 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
dframe = data.frame(resp2, elevation, slope, stand)
fit1 = lmer(resp2~elevation+slope+(1|stand), data = dframe)
}
mixed_fun()
simsthousand = rerun(1000, mixed_fun())
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
## boundary (singular) fit: see ?isSingular
library(tidyverse)
## ── Attaching packages ────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.2.0 ✔ readr 1.3.1
## ✔ tibble 2.1.3 ✔ dplyr 0.8.3
## ✔ tidyr 1.0.0 ✔ stringr 1.4.0
## ✔ ggplot2 3.2.0 ✔ forcats 0.4.0
## ── Conflicts ───────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ tidyr::expand() masks Matrix::expand()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ tidyr::pack() masks Matrix::pack()
## ✖ tidyr::unpack() masks Matrix::unpack()
library(broom)
library(purrr)
variances = simsthousand %>% map_dfr(tidy, effects = "ran_pars", scales = "vcov")
head(variances,6)
## # A tibble: 6 x 3
## term group estimate
## <chr> <chr> <dbl>
## 1 var_(Intercept).stand stand 2.02
## 2 var_Observation.Residual Residual 1.03
## 3 var_(Intercept).stand stand 1.03
## 4 var_Observation.Residual Residual 0.812
## 5 var_(Intercept).stand stand 5.76
## 6 var_Observation.Residual Residual 1.22
library(ggplot2)
library(dplyr)
stand_sims = c(10, 20, 100) %>%
set_names() %>%
map(~replicate(1000, mixed_fun(nstand = .x)))
stand_vars = stand_sims %>%
modify_depth(2, ~tidy(.x, effects = "ran_pars", scales = "vcov")) %>%
map_dfr(bind_rows, .id = "id") %>%
filter(group == "stand")
ggplot(stand_vars, aes(x = estimate)) +
geom_density(fill = "orange", alpha = "0.25") +
facet_wrap(~id) +
geom_vline(xintercept = 4) +theme(legend.position = "bottom", legend.key.width = unit(.1, "cm")) +
labs(x = "Estimated Variance", y = "Density")
As shown in the graphs, when sample size increases, variance will decrease.
coef = simsthousand %>%
map_dfr(tidy, effects="fixed") %>%
filter(term %in% c("elevation", "slope"))
coef$sequence = rep(1:1000, each=2)
coefmed = coef %>%
group_by(term) %>%
summarise(med=median(estimate))
plot2 = ggplot(coef, aes(sequence, estimate))+
geom_point(size=0.2)+
facet_wrap(~term)+
geom_hline(data=coefmed, aes(yintercept=med), size=0.4)+
labs(x="Replicated numbers", y="Estimate of coefficients")+
theme_bw()
plot2
As shown in the graphs, the median estimated coefficients values are 0.0047 and 0.0998, which are much close to initial parameters 0.005 and 0.1. But the estimated β1 and β2 are scattered, some β1 value are negative. The model does not fit well.