Parametric bootstrap for mixed-effects models

Julia is well-suited to implementing bootstrapping and other simulation-based methods for statistical models. The parametricbootstrap function in the MixedModels package provides an efficient parametric bootstrap for mixed-effects models.

MixedModels.parametricbootstrapFunction
parametricbootstrap([rng::AbstractRNG], nsamp::Integer, m::MixedModel{T}, ftype=T;
    β = coef(m), σ = m.σ, θ = m.θ, progress=true, optsum_overrides=(;))

Perform nsamp parametric bootstrap replication fits of m, returning a MixedModelBootstrap.

The default random number generator is Random.GLOBAL_RNG.

ftype can be used to store the computed bootstrap values in a lower precision. ftype is not a named argument because named arguments are not used in method dispatch and thus specialization. In other words, having ftype as a positional argument has some potential performance benefits.

Keyword Arguments

  • β, σ, and θ are the values of m's parameters for simulating the responses.
  • σ is only valid for LinearMixedModel and GeneralizedLinearMixedModel for

families with a dispersion parameter.

  • progress controls whether the progress bar is shown. Note that the progress

bar is automatically disabled for non-interactive (i.e. logging) contexts.

  • optsum_overrides is used to override values of OptSummary in the models

fit during the bootstrapping process. For example, optsum_overrides=(;ftol_rel=1e-08) reduces the convergence criterion, which can greatly speed up the bootstrap fits. Taking advantage of this speed up to increase n can often lead to better estimates of coverage intervals.

source

The parametric bootstrap

Bootstrapping is a family of procedures for generating sample values of a statistic, allowing for visualization of the distribution of the statistic or for inference from this sample of values.

A parametric bootstrap is used with a parametric model, m, that has been fit to data. The procedure is to simulate n response vectors from m using the estimated parameter values and refit m to these responses in turn, accumulating the statistics of interest at each iteration.

The parameters of a LinearMixedModel object are the fixed-effects parameters, β, the standard deviation, σ, of the per-observation noise, and the covariance parameter, θ, that defines the variance-covariance matrices of the random effects.

For example, a simple linear mixed-effects model for the Dyestuff data in the lme4 package for R is fit by

using DataFrames
using Gadfly          # plotting package
using MixedModels
using Random
dyestuff = MixedModels.dataset(:dyestuff)
m1 = fit(MixedModel, @formula(yield ~ 1 + (1 | batch)), dyestuff)
Est.SEzpσ_batch
(Intercept)1527.500017.694686.33<1e-9937.2603
Residual49.5101

To bootstrap the model parameters, first initialize a random number generator then create a bootstrap sample and extract the tbl property, which is a Table - a lightweight dataframe-like object.

const rng = MersenneTwister(1234321);
samp = parametricbootstrap(rng, 10_000, m1);
tbl = samp.tbl
Table with 5 columns and 10000 rows:
      obj      β1       σ        σ1        θ1
    ┌────────────────────────────────────────────────
 1  │ 339.022  1509.13  67.4315  14.312    0.212245
 2  │ 322.689  1538.08  47.9831  25.5673   0.53284
 3  │ 324.002  1508.02  50.1346  21.7622   0.434076
 4  │ 331.887  1538.47  53.2238  41.0559   0.771383
 5  │ 317.771  1520.62  45.2975  19.1802   0.423428
 6  │ 315.181  1536.94  36.7556  49.1832   1.33812
 7  │ 333.641  1519.88  53.8161  46.712    0.867993
 8  │ 325.729  1528.43  47.8989  37.6367   0.785752
 9  │ 311.601  1497.46  41.4     15.1257   0.365355
 10 │ 335.244  1532.65  64.616   0.0       0.0
 11 │ 327.935  1552.54  57.2036  0.485275  0.00848329
 12 │ 323.861  1519.28  49.355   24.3703   0.493776
 13 │ 332.736  1509.04  59.6272  18.2905   0.306747
 14 │ 328.243  1531.7   51.5431  32.4743   0.630042
 15 │ 336.186  1536.17  64.0205  15.243    0.238096
 16 │ 329.468  1526.42  58.6856  0.0       0.0
 17 │ 320.086  1517.67  43.218   35.9663   0.832207
 ⋮  │    ⋮        ⋮        ⋮        ⋮          ⋮

A density plot of the estimates of σ, the residual standard deviation, can be created as

plot(x = tbl.σ, Geom.density, Guide.xlabel("Parametric bootstrap estimates of σ"))
Parametric bootstrap estimates of σ 0 50 100 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0 18.5 19.0 19.5 20.0 20.5 21.0 21.5 22.0 22.5 23.0 23.5 24.0 24.5 25.0 25.5 26.0 26.5 27.0 27.5 28.0 28.5 29.0 29.5 30.0 30.5 31.0 31.5 32.0 32.5 33.0 33.5 34.0 34.5 35.0 35.5 36.0 36.5 37.0 37.5 38.0 38.5 39.0 39.5 40.0 40.5 41.0 41.5 42.0 42.5 43.0 43.5 44.0 44.5 45.0 45.5 46.0 46.5 47.0 47.5 48.0 48.5 49.0 49.5 50.0 50.5 51.0 51.5 52.0 52.5 53.0 53.5 54.0 54.5 55.0 55.5 56.0 56.5 57.0 57.5 58.0 58.5 59.0 59.5 60.0 60.5 61.0 61.5 62.0 62.5 63.0 63.5 64.0 64.5 65.0 65.5 66.0 66.5 67.0 67.5 68.0 68.5 69.0 69.5 70.0 70.5 71.0 71.5 72.0 72.5 73.0 73.5 74.0 74.5 75.0 75.5 76.0 76.5 77.0 77.5 78.0 78.5 79.0 79.5 80.0 80.5 81.0 81.5 82.0 82.5 83.0 83.5 84.0 84.5 85.0 85.5 86.0 86.5 87.0 87.5 88.0 88.5 89.0 89.5 90.0 90.5 91.0 91.5 92.0 92.5 93.0 93.5 94.0 94.5 95.0 95.5 96.0 96.5 97.0 97.5 98.0 98.5 99.0 99.5 100.0 0 100 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.0000 0.0025 0.0050 0.0075 0.0100 0.0125 0.0150 0.0175 0.0200 0.0225 0.0250 0.0275 0.0300 0.0325 0.0350 0.0375 0.0400 0.0425 0.0450 0.0475 0.0500 0.0525 0.0550 0.0575 0.0600 0.0625 0.0000 0.0002 0.0004 0.0006 0.0008 0.0010 0.0012 0.0014 0.0016 0.0018 0.0020 0.0022 0.0024 0.0026 0.0028 0.0030 0.0032 0.0034 0.0036 0.0038 0.0040 0.0042 0.0044 0.0046 0.0048 0.0050 0.0052 0.0054 0.0056 0.0058 0.0060 0.0062 0.0064 0.0066 0.0068 0.0070 0.0072 0.0074 0.0076 0.0078 0.0080 0.0082 0.0084 0.0086 0.0088 0.0090 0.0092 0.0094 0.0096 0.0098 0.0100 0.0102 0.0104 0.0106 0.0108 0.0110 0.0112 0.0114 0.0116 0.0118 0.0120 0.0122 0.0124 0.0126 0.0128 0.0130 0.0132 0.0134 0.0136 0.0138 0.0140 0.0142 0.0144 0.0146 0.0148 0.0150 0.0152 0.0154 0.0156 0.0158 0.0160 0.0162 0.0164 0.0166 0.0168 0.0170 0.0172 0.0174 0.0176 0.0178 0.0180 0.0182 0.0184 0.0186 0.0188 0.0190 0.0192 0.0194 0.0196 0.0198 0.0200 0.0202 0.0204 0.0206 0.0208 0.0210 0.0212 0.0214 0.0216 0.0218 0.0220 0.0222 0.0224 0.0226 0.0228 0.0230 0.0232 0.0234 0.0236 0.0238 0.0240 0.0242 0.0244 0.0246 0.0248 0.0250 0.0252 0.0254 0.0256 0.0258 0.0260 0.0262 0.0264 0.0266 0.0268 0.0270 0.0272 0.0274 0.0276 0.0278 0.0280 0.0282 0.0284 0.0286 0.0288 0.0290 0.0292 0.0294 0.0296 0.0298 0.0300 0.0302 0.0304 0.0306 0.0308 0.0310 0.0312 0.0314 0.0316 0.0318 0.0320 0.0322 0.0324 0.0326 0.0328 0.0330 0.0332 0.0334 0.0336 0.0338 0.0340 0.0342 0.0344 0.0346 0.0348 0.0350 0.0352 0.0354 0.0356 0.0358 0.0360 0.0362 0.0364 0.0366 0.0368 0.0370 0.0372 0.0374 0.0376 0.0378 0.0380 0.0382 0.0384 0.0386 0.0388 0.0390 0.0392 0.0394 0.0396 0.0398 0.0400 0.0402 0.0404 0.0406 0.0408 0.0410 0.0412 0.0414 0.0416 0.0418 0.0420 0.0422 0.0424 0.0426 0.0428 0.0430 0.0432 0.0434 0.0436 0.0438 0.0440 0.0442 0.0444 0.0446 0.0448 0.0450 0.0452 0.0454 0.0456 0.0458 0.0460 0.0462 0.0464 0.0466 0.0468 0.0470 0.0472 0.0474 0.0476 0.0478 0.0480 0.0482 0.0484 0.0486 0.0488 0.0490 0.0492 0.0494 0.0496 0.0498 0.0500 0.0502 0.0504 0.0506 0.0508 0.0510 0.0512 0.0514 0.0516 0.0518 0.0520 0.0522 0.0524 0.0526 0.0528 0.0530 0.0532 0.0534 0.0536 0.0538 0.0540 0.0542 0.0544 0.0546 0.0548 0.0550 0.0552 0.0554 0.0556 0.0558 0.0560 0.0562 0.0564 0.0566 0.0568 0.0570 0.0572 0.0574 0.0576 0.0578 0.0580 0.0582 0.0584 0.0586 0.0588 0.0590 0.0592 0.0594 0.0596 0.0598 0.0600 0.0602 0.0 0.1

or, for the intercept parameter

plot(x = tbl.β1, Geom.density, Guide.xlabel("Parametric bootstrap estimates of β₁"))
Parametric bootstrap estimates of β₁ 1400 1450 1500 1550 1600 1650 1400 1410 1420 1430 1440 1450 1460 1470 1480 1490 1500 1510 1520 1530 1540 1550 1560 1570 1580 1590 1600 1610 1620 1630 1640 1650 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1400 1500 1600 1700 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0.000 0.005 0.010 0.015 0.020 0.025 0.000 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.0000 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007 0.0008 0.0009 0.0010 0.0011 0.0012 0.0013 0.0014 0.0015 0.0016 0.0017 0.0018 0.0019 0.0020 0.0021 0.0022 0.0023 0.0024 0.0025 0.0026 0.0027 0.0028 0.0029 0.0030 0.0031 0.0032 0.0033 0.0034 0.0035 0.0036 0.0037 0.0038 0.0039 0.0040 0.0041 0.0042 0.0043 0.0044 0.0045 0.0046 0.0047 0.0048 0.0049 0.0050 0.0051 0.0052 0.0053 0.0054 0.0055 0.0056 0.0057 0.0058 0.0059 0.0060 0.0061 0.0062 0.0063 0.0064 0.0065 0.0066 0.0067 0.0068 0.0069 0.0070 0.0071 0.0072 0.0073 0.0074 0.0075 0.0076 0.0077 0.0078 0.0079 0.0080 0.0081 0.0082 0.0083 0.0084 0.0085 0.0086 0.0087 0.0088 0.0089 0.0090 0.0091 0.0092 0.0093 0.0094 0.0095 0.0096 0.0097 0.0098 0.0099 0.0100 0.0101 0.0102 0.0103 0.0104 0.0105 0.0106 0.0107 0.0108 0.0109 0.0110 0.0111 0.0112 0.0113 0.0114 0.0115 0.0116 0.0117 0.0118 0.0119 0.0120 0.0121 0.0122 0.0123 0.0124 0.0125 0.0126 0.0127 0.0128 0.0129 0.0130 0.0131 0.0132 0.0133 0.0134 0.0135 0.0136 0.0137 0.0138 0.0139 0.0140 0.0141 0.0142 0.0143 0.0144 0.0145 0.0146 0.0147 0.0148 0.0149 0.0150 0.0151 0.0152 0.0153 0.0154 0.0155 0.0156 0.0157 0.0158 0.0159 0.0160 0.0161 0.0162 0.0163 0.0164 0.0165 0.0166 0.0167 0.0168 0.0169 0.0170 0.0171 0.0172 0.0173 0.0174 0.0175 0.0176 0.0177 0.0178 0.0179 0.0180 0.0181 0.0182 0.0183 0.0184 0.0185 0.0186 0.0187 0.0188 0.0189 0.0190 0.0191 0.0192 0.0193 0.0194 0.0195 0.0196 0.0197 0.0198 0.0199 0.0200 0.0201 0.0202 0.0203 0.0204 0.0205 0.0206 0.0207 0.0208 0.0209 0.0210 0.0211 0.0212 0.0213 0.0214 0.0215 0.0216 0.0217 0.0218 0.0219 0.0220 0.0221 0.0222 0.0223 0.0224 0.0225 0.0226 0.0227 0.0228 0.0229 0.0230 0.0231 0.0232 0.0233 0.0234 0.0235 0.0236 0.0237 0.0238 0.0239 0.0240 0.0241 0.0242 0.0243 0.0244 0.0245 0.0246 0.0247 0.0248 0.0249 0.0250 0.000 0.025

A density plot of the estimates of the standard deviation of the random effects is obtained as

plot(x = tbl.σ1, Geom.density,
    Guide.xlabel("Parametric bootstrap estimates of σ₁"))
Parametric bootstrap estimates of σ₁ -50 0 50 100 150 -50 -40 -30 -20 -10 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 -50 -49 -48 -47 -46 -45 -44 -43 -42 -41 -40 -39 -38 -37 -36 -35 -34 -33 -32 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -21 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 -50 0 50 100 150 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0.00 0.01 0.02 0.03 0.000 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013 0.014 0.015 0.016 0.017 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.026 0.027 0.028 0.029 0.030 0.031 0.0000 0.0001 0.0002 0.0003 0.0004 0.0005 0.0006 0.0007 0.0008 0.0009 0.0010 0.0011 0.0012 0.0013 0.0014 0.0015 0.0016 0.0017 0.0018 0.0019 0.0020 0.0021 0.0022 0.0023 0.0024 0.0025 0.0026 0.0027 0.0028 0.0029 0.0030 0.0031 0.0032 0.0033 0.0034 0.0035 0.0036 0.0037 0.0038 0.0039 0.0040 0.0041 0.0042 0.0043 0.0044 0.0045 0.0046 0.0047 0.0048 0.0049 0.0050 0.0051 0.0052 0.0053 0.0054 0.0055 0.0056 0.0057 0.0058 0.0059 0.0060 0.0061 0.0062 0.0063 0.0064 0.0065 0.0066 0.0067 0.0068 0.0069 0.0070 0.0071 0.0072 0.0073 0.0074 0.0075 0.0076 0.0077 0.0078 0.0079 0.0080 0.0081 0.0082 0.0083 0.0084 0.0085 0.0086 0.0087 0.0088 0.0089 0.0090 0.0091 0.0092 0.0093 0.0094 0.0095 0.0096 0.0097 0.0098 0.0099 0.0100 0.0101 0.0102 0.0103 0.0104 0.0105 0.0106 0.0107 0.0108 0.0109 0.0110 0.0111 0.0112 0.0113 0.0114 0.0115 0.0116 0.0117 0.0118 0.0119 0.0120 0.0121 0.0122 0.0123 0.0124 0.0125 0.0126 0.0127 0.0128 0.0129 0.0130 0.0131 0.0132 0.0133 0.0134 0.0135 0.0136 0.0137 0.0138 0.0139 0.0140 0.0141 0.0142 0.0143 0.0144 0.0145 0.0146 0.0147 0.0148 0.0149 0.0150 0.0151 0.0152 0.0153 0.0154 0.0155 0.0156 0.0157 0.0158 0.0159 0.0160 0.0161 0.0162 0.0163 0.0164 0.0165 0.0166 0.0167 0.0168 0.0169 0.0170 0.0171 0.0172 0.0173 0.0174 0.0175 0.0176 0.0177 0.0178 0.0179 0.0180 0.0181 0.0182 0.0183 0.0184 0.0185 0.0186 0.0187 0.0188 0.0189 0.0190 0.0191 0.0192 0.0193 0.0194 0.0195 0.0196 0.0197 0.0198 0.0199 0.0200 0.0201 0.0202 0.0203 0.0204 0.0205 0.0206 0.0207 0.0208 0.0209 0.0210 0.0211 0.0212 0.0213 0.0214 0.0215 0.0216 0.0217 0.0218 0.0219 0.0220 0.0221 0.0222 0.0223 0.0224 0.0225 0.0226 0.0227 0.0228 0.0229 0.0230 0.0231 0.0232 0.0233 0.0234 0.0235 0.0236 0.0237 0.0238 0.0239 0.0240 0.0241 0.0242 0.0243 0.0244 0.0245 0.0246 0.0247 0.0248 0.0249 0.0250 0.0251 0.0252 0.0253 0.0254 0.0255 0.0256 0.0257 0.0258 0.0259 0.0260 0.0261 0.0262 0.0263 0.0264 0.0265 0.0266 0.0267 0.0268 0.0269 0.0270 0.0271 0.0272 0.0273 0.0274 0.0275 0.0276 0.0277 0.0278 0.0279 0.0280 0.0281 0.0282 0.0283 0.0284 0.0285 0.0286 0.0287 0.0288 0.0289 0.0290 0.0291 0.0292 0.0293 0.0294 0.0295 0.0296 0.0297 0.0298 0.0299 0.0300 0.0301 0.00 0.03

Notice that this density plot has a spike, or mode, at zero. Although this mode appears to be diffuse, this is an artifact of the way that density plots are created. In fact, it is a pulse, as can be seen from a histogram.

plot(x = tbl.σ1, Geom.histogram,
    Guide.xlabel("Parametric bootstrap estimates of σ₁"))
Parametric bootstrap estimates of σ₁ 0 50 100 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0 18.5 19.0 19.5 20.0 20.5 21.0 21.5 22.0 22.5 23.0 23.5 24.0 24.5 25.0 25.5 26.0 26.5 27.0 27.5 28.0 28.5 29.0 29.5 30.0 30.5 31.0 31.5 32.0 32.5 33.0 33.5 34.0 34.5 35.0 35.5 36.0 36.5 37.0 37.5 38.0 38.5 39.0 39.5 40.0 40.5 41.0 41.5 42.0 42.5 43.0 43.5 44.0 44.5 45.0 45.5 46.0 46.5 47.0 47.5 48.0 48.5 49.0 49.5 50.0 50.5 51.0 51.5 52.0 52.5 53.0 53.5 54.0 54.5 55.0 55.5 56.0 56.5 57.0 57.5 58.0 58.5 59.0 59.5 60.0 60.5 61.0 61.5 62.0 62.5 63.0 63.5 64.0 64.5 65.0 65.5 66.0 66.5 67.0 67.5 68.0 68.5 69.0 69.5 70.0 70.5 71.0 71.5 72.0 72.5 73.0 73.5 74.0 74.5 75.0 75.5 76.0 76.5 77.0 77.5 78.0 78.5 79.0 79.5 80.0 80.5 81.0 81.5 82.0 82.5 83.0 83.5 84.0 84.5 85.0 85.5 86.0 86.5 87.0 87.5 88.0 88.5 89.0 89.5 90.0 90.5 91.0 91.5 92.0 92.5 93.0 93.5 94.0 94.5 95.0 95.5 96.0 96.5 97.0 97.5 98.0 98.5 99.0 99.5 100.0 0 100 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0 500 1000 0 50 100 150 200 250 300 350 400 450 500 550 600 650 700 750 800 850 900 950 1000 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180 185 190 195 200 205 210 215 220 225 230 235 240 245 250 255 260 265 270 275 280 285 290 295 300 305 310 315 320 325 330 335 340 345 350 355 360 365 370 375 380 385 390 395 400 405 410 415 420 425 430 435 440 445 450 455 460 465 470 475 480 485 490 495 500 505 510 515 520 525 530 535 540 545 550 555 560 565 570 575 580 585 590 595 600 605 610 615 620 625 630 635 640 645 650 655 660 665 670 675 680 685 690 695 700 705 710 715 720 725 730 735 740 745 750 755 760 765 770 775 780 785 790 795 800 805 810 815 820 825 830 835 840 845 850 855 860 865 870 875 880 885 890 895 900 905 910 915 920 925 930 935 940 945 950 955 960 965 970 975 980 985 990 995 1000 0 1000

The bootstrap sample can be used to generate intervals that cover a certain percentage of the bootstrapped values. We refer to these as "coverage intervals", similar to a confidence interval. The shortest such intervals, obtained with the shortestcovint extractor, correspond to a highest posterior density interval in Bayesian inference.

MixedModels.shortestcovintFunction
shortestcovint(v, level = 0.95)

Return the shortest interval containing level proportion of the values of v

source
shortestcovint(bsamp::MixedModelFitCollection, level = 0.95)

Return the shortest interval containing level proportion for each parameter from bsamp.allpars.

Warning

Currently, correlations that are systematically zero are included in the the result. This may change in a future release without being considered a breaking change.

source

We generate these directly from the original bootstrap object:

Table(shortestcovint(samp))
Table with 5 columns and 3 rows:
     type  group     names        lower    upper
   ┌──────────────────────────────────────────────
 1 │ β     missing   (Intercept)  1492.54  1561.34
 2 │ σ     batch     (Intercept)  0.0      54.7043
 3 │ σ     residual  missing      35.4909  63.0209

A value of zero for the standard deviation of the random effects is an example of a singular covariance. It is easy to detect the singularity in the case of a scalar random-effects term. However, it is not as straightforward to detect singularity in vector-valued random-effects terms.

For example, if we bootstrap a model fit to the sleepstudy data

sleepstudy = MixedModels.dataset(:sleepstudy)
contrasts = Dict(:subj => Grouping())
m2 = let f = @formula reaction ~ 1+days+(1+days|subj)
    fit(MixedModel, f, sleepstudy; contrasts)
end
Est.SEzpσ_subj
(Intercept)251.40516.632337.91<1e-9923.7805
days10.46731.50226.97<1e-115.7168
Residual25.5918
samp2 = parametricbootstrap(rng, 10_000, m2);
tbl2 = samp2.tbl
Table with 10 columns and 10000 rows:
      obj      β1       β2       σ        σ1       σ2       ρ1          ⋯
    ┌────────────────────────────────────────────────────────────────────
 1  │ 1762.97  262.397  10.5117  26.2691  24.8119  6.86013  -0.335778   ⋯
 2  │ 1761.29  252.753  10.9396  27.4071  15.4139  5.27725  0.191491    ⋯
 3  │ 1760.12  244.773  14.1153  27.7064  18.1545  3.77585  0.501708    ⋯
 4  │ 1728.02  256.885  9.90894  24.3406  22.8058  4.62388  -0.125449   ⋯
 5  │ 1739.12  241.968  12.9145  26.1862  8.27939  5.21775  0.596434    ⋯
 6  │ 1779.57  249.305  11.2124  27.2767  24.9131  7.15134  0.220329    ⋯
 7  │ 1765.37  240.264  10.7107  27.3333  25.2447  4.18552  0.613865    ⋯
 8  │ 1727.31  253.876  9.17989  24.8219  22.5107  3.72496  -0.167116   ⋯
 9  │ 1746.59  264.797  10.315   25.6272  21.3612  5.06129  0.310146    ⋯
 10 │ 1755.46  256.464  10.4106  25.4156  35.3511  4.95412  -0.195481   ⋯
 11 │ 1773.51  260.967  11.0385  28.4814  21.2083  4.39551  1.0         ⋯
 12 │ 1690.61  258.852  10.3472  21.0322  26.1479  4.99185  -0.0787605  ⋯
 13 │ 1742.15  251.951  8.57777  24.3526  28.4102  5.7392   0.139818    ⋯
 14 │ 1733.94  260.473  9.68852  24.1964  20.8341  6.17182  0.377655    ⋯
 15 │ 1781.65  249.654  11.0241  29.552   11.5514  5.28092  0.498551    ⋯
 16 │ 1790.19  247.356  9.46489  28.0847  31.4617  6.25443  0.00731404  ⋯
 17 │ 1740.19  245.537  11.243   25.5401  14.8452  5.53331  0.258929    ⋯
 ⋮  │    ⋮        ⋮        ⋮        ⋮        ⋮        ⋮         ⋮       ⋱

the singularity can be exhibited as a standard deviation of zero or as a correlation of $\pm1$.

shortestcovint(samp2)
6-element Vector{NamedTuple{(:type, :group, :names, :lower, :upper)}}:
 (type = "β", group = missing, names = "(Intercept)", lower = 238.5828600121597, upper = 263.89217662125895)
 (type = "β", group = missing, names = "days", lower = 7.53963829955738, upper = 13.368161276142278)
 (type = "σ", group = "subj", names = "(Intercept)", lower = 10.507850446277885, upper = 33.218443649036274)
 (type = "σ", group = "subj", names = "days", lower = 3.0249364539176846, upper = 7.675266461784905)
 (type = "ρ", group = "subj", names = "(Intercept), days", lower = -0.4053576235224805, upper = 1.0)
 (type = "σ", group = "residual", names = missing, lower = 22.656763022378666, upper = 28.43122140514219)

A histogram of the estimated correlations from the bootstrap sample has a spike at +1.

plot(x = tbl2.ρ1, Geom.histogram,
    Guide.xlabel("Parametric bootstrap samples of correlation of random effects"))
Parametric bootstrap samples of correlation of random effects -1.0 -0.5 0.0 0.5 1.0 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 -1.00 -0.99 -0.98 -0.97 -0.96 -0.95 -0.94 -0.93 -0.92 -0.91 -0.90 -0.89 -0.88 -0.87 -0.86 -0.85 -0.84 -0.83 -0.82 -0.81 -0.80 -0.79 -0.78 -0.77 -0.76 -0.75 -0.74 -0.73 -0.72 -0.71 -0.70 -0.69 -0.68 -0.67 -0.66 -0.65 -0.64 -0.63 -0.62 -0.61 -0.60 -0.59 -0.58 -0.57 -0.56 -0.55 -0.54 -0.53 -0.52 -0.51 -0.50 -0.49 -0.48 -0.47 -0.46 -0.45 -0.44 -0.43 -0.42 -0.41 -0.40 -0.39 -0.38 -0.37 -0.36 -0.35 -0.34 -0.33 -0.32 -0.31 -0.30 -0.29 -0.28 -0.27 -0.26 -0.25 -0.24 -0.23 -0.22 -0.21 -0.20 -0.19 -0.18 -0.17 -0.16 -0.15 -0.14 -0.13 -0.12 -0.11 -0.10 -0.09 -0.08 -0.07 -0.06 -0.05 -0.04 -0.03 -0.02 -0.01 0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.10 0.11 0.12 0.13 0.14 0.15 0.16 0.17 0.18 0.19 0.20 0.21 0.22 0.23 0.24 0.25 0.26 0.27 0.28 0.29 0.30 0.31 0.32 0.33 0.34 0.35 0.36 0.37 0.38 0.39 0.40 0.41 0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.49 0.50 0.51 0.52 0.53 0.54 0.55 0.56 0.57 0.58 0.59 0.60 0.61 0.62 0.63 0.64 0.65 0.66 0.67 0.68 0.69 0.70 0.71 0.72 0.73 0.74 0.75 0.76 0.77 0.78 0.79 0.80 0.81 0.82 0.83 0.84 0.85 0.86 0.87 0.88 0.89 0.90 0.91 0.92 0.93 0.94 0.95 0.96 0.97 0.98 0.99 1.00 -1 0 1 h,j,k,l,arrows,drag to pan i,o,+,-,scroll,shift-drag to zoom r,dbl-click to reset c for coordinates ? for help ? 0 100 200 300 400 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320 340 360 380 400 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 156 158 160 162 164 166 168 170 172 174 176 178 180 182 184 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 218 220 222 224 226 228 230 232 234 236 238 240 242 244 246 248 250 252 254 256 258 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 294 296 298 300 302 304 306 308 310 312 314 316 318 320 322 324 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 358 360 362 364 366 368 370 372 374 376 378 380 382 384 386 388 390 392 394 396 398 400 0 500

or, as a count,

count(tbl2.ρ1 .≈ 1)
306

Close examination of the histogram shows a few values of -1.

count(tbl2.ρ1 .≈ -1)
2

Furthermore there are even a few cases where the estimate of the standard deviation of the random effect for the intercept is zero.

count(tbl2.σ1 .≈ 0)
5

There is a general condition to check for singularity of an estimated covariance matrix or matrices in a bootstrap sample. The parameter optimized in the estimation is θ, the relative covariance parameter. Some of the elements of this parameter vector must be non-negative and, when one of these components is approximately zero, one of the covariance matrices will be singular.

The issingular method for a MixedModel object that tests if a parameter vector θ corresponds to a boundary or singular fit.

This operation is encapsulated in a method for the issingular function.

count(issingular(samp2))
313

Reduced Precision Bootstrap

parametricbootstrap accepts an optional keyword argument optsum_overrides, which can be used to override the convergence criteria for bootstrap replicates. One possibility is setting ftol_rel=1e-8, i.e., considering the model converged when the relative change in the objective between optimizer iterations is smaller than 0.00000001. This threshold corresponds approximately to the precision from treating the value of the objective as a single precision (Float32) number, while not changing the precision of the intermediate computations. The resultant loss in precision will generally be smaller than the variation that the bootstrap captures, but can greatly speed up the fitting process for each replicates, especially for large models. More directly, lowering the fit quality for each replicate will reduce the quality of each replicate, but this may be more than compensated for by the ability to fit a much larger number of replicates in the same time.

t = @timed parametricbootstrap(MersenneTwister(42), 1000, m2; progress=false)
t.time
0.702800708
optsum_overrides = (; ftol_rel=1e-8)
t = @timed parametricbootstrap(MersenneTwister(42), 1000, m2; optsum_overrides, progress=false)
t.time
0.687348516

Distributed Computing and the Bootstrap

Earlier versions of MixedModels.jl supported a multi-threaded bootstrap via the use_threads keyword argument. However, with improved BLAS multithreading, the Julia-level threads often wound up competing with the BLAS threads, leading to no improvement or even a worsening of performance when use_threads=true. Nonetheless, the bootstrap is a classic example of an embarrassingly parallel problem and so we provide a few convenience methods for combining results computed separately. In particular, there are vcat and an optimized reduce(::typeof(vcat)) methods for MixedModelBootstrap objects. For computers with many processors (as opposed to a single processor with several cores) or for computing clusters, these provide a convenient way to split the computation across nodes.

using Distributed
using ProgressMeter
# you already have 1 proc by default, so add the number of additional cores with `addprocs`
# you need at least as many RNGs as cores you want to use in parallel
# but you shouldn't use all of your cores because nested within this
# is the multithreading of the linear algebra
@info "Currently using $(nprocs()) processors total and $(nworkers()) for work"

# copy everything to workers
@showprogress for w in workers()
    remotecall_fetch(() -> coefnames(m2), w)
end

# split the replicates across the workers
# this rounds down, so if the number of workers doesn't divide the
# number of replicates, you'll be a few replicates short!
n_replicates = 1000
n_rep_per_worker = n_replicates ÷ nworkers()
# NB: You need a different seed/RNG for each worker otherwise you will
# have copies of the same replicates and not independent replicates!
pb_map = @showprogress pmap(MersenneTwister.(1:nworkers())) do rng
    parametricbootstrap(rng, n_rep_per_worker, m2; optsum_overrides)
end;

# get rid of all the workers
# rmprocs(workers())

confint(reduce(vcat, pb_map))
DictTable with 2 columns and 6 rows:
 par   lower      upper
 ────┬───────────────────
 β1  │ 236.59     264.035
 β2  │ 7.75279    13.3734
 ρ1  │ -0.424371  1.0
 σ   │ 22.4485    28.2745
 σ1  │ 10.6217    32.5576
 σ2  │ 3.18136    7.74161