Question 8

Generate test data:

set.seed(1)
x <- rnorm(100)
eps <- rnorm(100)
beta0 <- 2.731
beta1 <- -3.296
beta2 <- 5.117
beta3 <- -1.793
y <- beta0 + beta1 * x + beta2 * x^2 + beta3 * x^3 + eps
plot(x, y)

inp <- data.frame(x, y)

(c) Fit with best subsets selection

bss <- regsubsets(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, nvmax = 10)
bss.summary <- summary(bss)
bss.summary
Subset selection object
Call: regsubsets.formula(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + 
    I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, 
    nvmax = 10)
10 Variables  (and intercept)
        Forced in Forced out
x           FALSE      FALSE
I(x^2)      FALSE      FALSE
I(x^3)      FALSE      FALSE
I(x^4)      FALSE      FALSE
I(x^5)      FALSE      FALSE
I(x^6)      FALSE      FALSE
I(x^7)      FALSE      FALSE
I(x^8)      FALSE      FALSE
I(x^9)      FALSE      FALSE
I(x^10)     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: exhaustive
          x   I(x^2) I(x^3) I(x^4) I(x^5) I(x^6) I(x^7) I(x^8) I(x^9) I(x^10)
1  ( 1 )  "*" " "    " "    " "    " "    " "    " "    " "    " "    " "    
2  ( 1 )  " " "*"    "*"    " "    " "    " "    " "    " "    " "    " "    
3  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    " "    " "    " "    
4  ( 1 )  "*" "*"    "*"    " "    "*"    " "    " "    " "    " "    " "    
5  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    " "    " "    " "    " "    
6  ( 1 )  "*" "*"    "*"    " "    " "    " "    "*"    "*"    "*"    " "    
7  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    " "    "*"    " "    "*"    
8  ( 1 )  "*" "*"    "*"    "*"    " "    "*"    " "    "*"    "*"    "*"    
9  ( 1 )  "*" "*"    "*"    "*"    "*"    "*"    " "    "*"    "*"    "*"    
10  ( 1 ) "*" "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    
par(mfrow=c(1,3))
plot(bss.summary$adjr2, xlab = 'Number of variables', ylab = 'Adjusted R2', type = 'l')
rsq.max.idx <- which.max(bss.summary$adjr2)
points(rsq.max.idx, bss.summary$adjr2[rsq.max.idx], col = 'red', cex = 2, pch = 20)
cp.min.idx <- which.min(bss.summary$cp)
plot(bss.summary$cp, xlab = 'Number of variables', ylab = 'Cp', type = 'l')
points(cp.min.idx, bss.summary$cp[cp.min.idx], col = 'red', cex = 2, pch = 20)
bic.min.idx <- which.min(bss.summary$bic)
plot(bss.summary$bic, xlab = 'Number of variables', ylab = 'BIC', type = 'l')
points(bic.min.idx, bss.summary$bic[bic.min.idx], col = 'red', cex = 2, pch = 20)
par(mfrow=c(1,1))

plot(bss, scale = 'adjr2')

plot(bss, scale = 'Cp')

plot(bss, scale = 'bic')

According to adjusted \(R^2\) and \(C_p\), the best model contains 4 predictors: \(X\), \(X^2\), \(X^3\) and \(X^5\). According to BIC, the best model contains 3 predictors: \(X\), \(X^2\) and \(X^3\).

Get the coefficient estimates:

coef(bss, 3)
(Intercept)           x      I(x^2)      I(x^3) 
   2.792507   -3.320720    4.993209   -1.775361 

The coefficient estimates vs origin coefficients: \[ \beta_0 = 2.731 \quad \beta_1 = -3.296 \quad \beta_2 = 5.117 \quad \beta_3 = -1.793\\ \hat\beta_0 = 2.793 \quad \hat\beta_1 = -3.321 \quad \hat\beta_2 = 4.993\quad \hat\beta_3 = -1.775 \]

(d)

Fit with forward stepwise selection method:

fss <- regsubsets(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, method = 'forward', nvmax = 10)
fss.summary <- summary(fss)
fss.summary
Subset selection object
Call: regsubsets.formula(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + 
    I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, 
    method = "forward", nvmax = 10)
10 Variables  (and intercept)
        Forced in Forced out
x           FALSE      FALSE
I(x^2)      FALSE      FALSE
I(x^3)      FALSE      FALSE
I(x^4)      FALSE      FALSE
I(x^5)      FALSE      FALSE
I(x^6)      FALSE      FALSE
I(x^7)      FALSE      FALSE
I(x^8)      FALSE      FALSE
I(x^9)      FALSE      FALSE
I(x^10)     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: forward
          x   I(x^2) I(x^3) I(x^4) I(x^5) I(x^6) I(x^7) I(x^8) I(x^9) I(x^10)
1  ( 1 )  "*" " "    " "    " "    " "    " "    " "    " "    " "    " "    
2  ( 1 )  "*" "*"    " "    " "    " "    " "    " "    " "    " "    " "    
3  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    " "    " "    " "    
4  ( 1 )  "*" "*"    "*"    " "    "*"    " "    " "    " "    " "    " "    
5  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    " "    " "    " "    " "    
6  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    " "    " "    "*"    " "    
7  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    "*"    " "    "*"    " "    
8  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    "*"    "*"    "*"    " "    
9  ( 1 )  "*" "*"    "*"    " "    "*"    "*"    "*"    "*"    "*"    "*"    
10  ( 1 ) "*" "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    
par(mfrow=c(1,3))
plot(fss.summary$adjr2, xlab = 'Number of variables', ylab = 'Adjusted R2', type = 'l')
rsq.max.idx <- which.max(fss.summary$adjr2)
points(rsq.max.idx, fss.summary$adjr2[rsq.max.idx], col = 'red', cex = 2, pch = 20)
cp.min.idx <- which.min(fss.summary$cp)
plot(fss.summary$cp, xlab = 'Number of variables', ylab = 'Cp', type = 'l')
points(cp.min.idx, fss.summary$cp[cp.min.idx], col = 'red', cex = 2, pch = 20)
bic.min.idx <- which.min(fss.summary$bic)
plot(fss.summary$bic, xlab = 'Number of variables', ylab = 'BIC', type = 'l')
points(bic.min.idx, fss.summary$bic[bic.min.idx], col = 'red', cex = 2, pch = 20)

According to adjusted \(R^2\), the best model contains 5 predictors: \(X\) ~ \(X^5\). According to \(C_p\), the best model contains 4 predictors: \(X\), \(X^2\), \(X^3\) and \(X^5\). According to BIC, the best model contains 3 predictors: \(X\), \(X^2\) and \(X^3\).

Fit with backward stepwise selection method:

bks <- regsubsets(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, method = 'backward', nvmax = 10)
bks.summary <- summary(bks)
bks.summary
Subset selection object
Call: regsubsets.formula(y ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + 
    I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, 
    method = "backward", nvmax = 10)
10 Variables  (and intercept)
        Forced in Forced out
x           FALSE      FALSE
I(x^2)      FALSE      FALSE
I(x^3)      FALSE      FALSE
I(x^4)      FALSE      FALSE
I(x^5)      FALSE      FALSE
I(x^6)      FALSE      FALSE
I(x^7)      FALSE      FALSE
I(x^8)      FALSE      FALSE
I(x^9)      FALSE      FALSE
I(x^10)     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: backward
          x   I(x^2) I(x^3) I(x^4) I(x^5) I(x^6) I(x^7) I(x^8) I(x^9) I(x^10)
1  ( 1 )  " " " "    "*"    " "    " "    " "    " "    " "    " "    " "    
2  ( 1 )  " " "*"    "*"    " "    " "    " "    " "    " "    " "    " "    
3  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    " "    " "    " "    
4  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    " "    "*"    " "    
5  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    "*"    "*"    " "    
6  ( 1 )  "*" "*"    "*"    " "    " "    " "    " "    "*"    "*"    "*"    
7  ( 1 )  "*" "*"    "*"    " "    " "    "*"    " "    "*"    "*"    "*"    
8  ( 1 )  "*" "*"    "*"    "*"    " "    "*"    " "    "*"    "*"    "*"    
9  ( 1 )  "*" "*"    "*"    "*"    "*"    "*"    " "    "*"    "*"    "*"    
10  ( 1 ) "*" "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    
which.max(bks.summary$adjr2)
[1] 4
which.min(bks.summary$cp)
[1] 4
bks.summary$bic
 [1]  -57.68976 -279.28567 -419.95753 -418.81452 -414.48436 -410.22467 -406.16631
 [8] -402.40497 -397.81758 -393.38480
which.min(bks.summary$bic)
[1] 3
par(mfrow=c(1,3))
plot(bks.summary$adjr2, xlab = 'Number of variables', ylab = 'Adjusted R2', type = 'l')
rsq.max.idx <- which.max(bks.summary$adjr2)
points(rsq.max.idx, bks.summary$adjr2[rsq.max.idx], col = 'red', cex = 2, pch = 20)
cp.min.idx <- which.min(bks.summary$cp)
plot(bks.summary$cp, xlab = 'Number of variables', ylab = 'Cp', type = 'l')
points(cp.min.idx, bks.summary$cp[cp.min.idx], col = 'red', cex = 2, pch = 20)
bic.min.idx <- which.min(bks.summary$bic)
plot(bks.summary$bic, xlab = 'Number of variables', ylab = 'BIC', type = 'l')
points(bic.min.idx, bks.summary$bic[bic.min.idx], col = 'red', cex = 2, pch = 20)

The result is the same with forward stepwise selection methods. The results of forward/backward stepwise selection are basically the same with results of best subsets methods.

Get the coefficient estimates (which is the same with results of best subsets method in section (c)):

coef(fss, 3)
(Intercept)           x      I(x^2)      I(x^3) 
   2.792507   -3.320720    4.993209   -1.775361 
coef(bks, 3)
(Intercept)           x      I(x^2)      I(x^3) 
   2.792507   -3.320720    4.993209   -1.775361 

Use I() instead of poly

fss.poly <- regsubsets(y ~ poly(x, 10), data = inp, method = 'forward', nvmax = 10)
coef(fss.poly, 3)
 (Intercept) poly(x, 10)1 poly(x, 10)2 poly(x, 10)3 
    6.104218   -61.183673    50.894057   -26.582822 

So the wrong coefficient estimates show the poly(x, 10) is wrong here.

(e)

Fit with lasso model:

X <- data.frame(x, x^2, x^3, x^4, x^5, x^6, x^7, x^8, x^9, x^10)
lasso.cv <- cv.glmnet(as.matrix(X), y, alpha = 1)
plot(lasso.cv)

lbl <- lasso.cv$lambda.min
lasso.res <- glmnet(as.matrix(X), y, alpha = 1, lambda = lbl)
lasso.res$beta
10 x 1 sparse Matrix of class "dgCMatrix"
                s0
x    -3.250153e+00
x.2   4.719326e+00
x.3  -1.785540e+00
x.4   4.548949e-02
x.5   .           
x.6   6.696648e-04
x.7   .           
x.8   2.418415e-04
x.9   .           
x.10  1.191105e-05
lasso.res$a0
      s0 
2.906318 

The coefficient estimates vs origin coefficients: \[ \beta_0 = 2.731 \quad \beta_1 = -3.296 \quad \beta_2 = 5.117 \quad \beta_3 = -1.793\\ \hat\beta_0 = 2.906 \quad \hat\beta_1 = -3.250 \quad \hat\beta_2 = 4.719 \quad \hat\beta_3 = -1.786 \]

(f)

Fit \(Y = \beta_0 + \beta_7 X^7 + \epsilon\) with best subsets method:

beta7 <- 7.697
yf <- beta0 + beta7 * x^7 + eps
bsf <- regsubsets(yf ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, nvmax = 10)
bsf.summary <- summary(bsf)
bsf.summary
Subset selection object
Call: regsubsets.formula(yf ~ x + I(x^2) + I(x^3) + I(x^4) + I(x^5) + 
    I(x^6) + I(x^7) + I(x^8) + I(x^9) + I(x^10), data = inp, 
    nvmax = 10)
10 Variables  (and intercept)
        Forced in Forced out
x           FALSE      FALSE
I(x^2)      FALSE      FALSE
I(x^3)      FALSE      FALSE
I(x^4)      FALSE      FALSE
I(x^5)      FALSE      FALSE
I(x^6)      FALSE      FALSE
I(x^7)      FALSE      FALSE
I(x^8)      FALSE      FALSE
I(x^9)      FALSE      FALSE
I(x^10)     FALSE      FALSE
1 subsets of each size up to 10
Selection Algorithm: exhaustive
          x   I(x^2) I(x^3) I(x^4) I(x^5) I(x^6) I(x^7) I(x^8) I(x^9) I(x^10)
1  ( 1 )  " " " "    " "    " "    " "    " "    "*"    " "    " "    " "    
2  ( 1 )  " " "*"    " "    " "    " "    " "    "*"    " "    " "    " "    
3  ( 1 )  " " "*"    " "    " "    "*"    " "    "*"    " "    " "    " "    
4  ( 1 )  "*" "*"    "*"    " "    " "    " "    "*"    " "    " "    " "    
5  ( 1 )  "*" "*"    "*"    "*"    " "    " "    "*"    " "    " "    " "    
6  ( 1 )  "*" " "    "*"    " "    " "    "*"    "*"    "*"    " "    "*"    
7  ( 1 )  "*" " "    "*"    " "    "*"    "*"    "*"    "*"    " "    "*"    
8  ( 1 )  "*" "*"    "*"    "*"    " "    "*"    "*"    "*"    " "    "*"    
9  ( 1 )  "*" "*"    "*"    "*"    " "    "*"    "*"    "*"    "*"    "*"    
10  ( 1 ) "*" "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    "*"    
par(mfrow=c(1,3))
plot(bsf.summary$adjr2, xlab = 'Number of variables', ylab = 'Adjusted R2', type = 'l')
rsq.max.idx <- which.max(bsf.summary$adjr2)
points(rsq.max.idx, bsf.summary$adjr2[rsq.max.idx], col = 'red', cex = 2, pch = 20)
cp.min.idx <- which.min(bsf.summary$cp)
plot(bsf.summary$cp, xlab = 'Number of variables', ylab = 'Cp', type = 'l')
points(cp.min.idx, bsf.summary$cp[cp.min.idx], col = 'red', cex = 2, pch = 20)
bic.min.idx <- which.min(bsf.summary$bic)
plot(bsf.summary$bic, xlab = 'Number of variables', ylab = 'BIC', type = 'l')
points(bic.min.idx, bsf.summary$bic[bic.min.idx], col = 'red', cex = 2, pch = 20)

Compare the coefficients:

coef(bsf, 1)
(Intercept)      I(x^7) 
    2.68994     7.69777 

The coefficient estimates vs origin coefficients: \[ \beta_0 = 2.731 \quad \beta_7 = 7.697 \\ \hat\beta_0 = 2.690 \quad \hat\beta_1 = 7.698 \]

Fit with lasso:

X <- data.frame(x, x^2, x^3, x^4, x^5, x^6, x^7, x^8, x^9, x^10)
lasso.cv <- cv.glmnet(as.matrix(X), yf, alpha = 1)
plot(lasso.cv)

lbl <- lasso.cv$lambda.min
lasso.res <- glmnet(as.matrix(X), yf, alpha = 1, lambda = lbl)
lasso.res$beta
10 x 1 sparse Matrix of class "dgCMatrix"
              s0
x    .          
x.2  .          
x.3  .          
x.4  .          
x.5  .          
x.6  .          
x.7  7.436029866
x.8  .          
x.9  0.002537033
x.10 .          
lasso.res$a0
      s0 
3.734293 

The coefficient estimates vs origin coefficients: \[ \beta_0 = 2.731 \quad \beta_7 = 7.697 \\ \hat\beta_0 = 3.734 \quad \hat\beta_1 = 7.436 \] So for this model, the lasso give worse coefficients than best subsets.

Question 9

  1. and (b): generate data set, fit with linear regression and calculate test error:
set.seed(1)
train <- sample(1: nrow(College), nrow(College)/2)
test <- -train
lr.fit <- lm(Apps ~ ., data = College)
lr.pred <- predict(lr.fit, College[test, ])
mean((lr.pred - College[test, ]$Apps) ^ 2)
[1] 940062.9
summary(lr.fit)

Call:
lm(formula = Apps ~ ., data = College)

Residuals:
    Min      1Q  Median      3Q     Max 
-4908.8  -430.2   -29.5   322.3  7852.5 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -445.08413  408.32855  -1.090 0.276053    
PrivateYes  -494.14897  137.81191  -3.586 0.000358 ***
Accept         1.58581    0.04074  38.924  < 2e-16 ***
Enroll        -0.88069    0.18596  -4.736 2.60e-06 ***
Top10perc     49.92628    5.57824   8.950  < 2e-16 ***
Top25perc    -14.23448    4.47914  -3.178 0.001543 ** 
F.Undergrad    0.05739    0.03271   1.754 0.079785 .  
P.Undergrad    0.04445    0.03214   1.383 0.167114    
Outstate      -0.08587    0.01906  -4.506 7.64e-06 ***
Room.Board     0.15103    0.04829   3.127 0.001832 ** 
Books          0.02090    0.23841   0.088 0.930175    
Personal       0.03110    0.06308   0.493 0.622060    
PhD           -8.67850    4.63814  -1.871 0.061714 .  
Terminal      -3.33066    5.09494  -0.654 0.513492    
S.F.Ratio     15.38961   13.00622   1.183 0.237081    
perc.alumni    0.17867    4.10230   0.044 0.965273    
Expend         0.07790    0.01235   6.308 4.79e-10 ***
Grad.Rate      8.66763    2.94893   2.939 0.003390 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1041 on 759 degrees of freedom
Multiple R-squared:  0.9292,    Adjusted R-squared:  0.9276 
F-statistic: 585.9 on 17 and 759 DF,  p-value: < 2.2e-16

(c): fit with ridge regression and calculate test error:

set.seed(1)
inpx <- model.matrix(Apps ~ ., data = College)[, -1]
inpy <- College$Apps
cv.out <- cv.glmnet(inpx[train, ], inpy[train], alpha = 0)
rr.fit <- glmnet(inpx[train, ], inpy[train], alpha = 0, lambda = cv.out$lambda.min)
rr.pred <- predict(rr.fit, inpx[test, ], s = cv.out$lambda.min)
mean((rr.pred - inpy[test]) ^ 2)
[1] 1038427

(d): fit with lasso, calculate the test error and show coefficient estimates:

set.seed(1)
cv.out <- cv.glmnet(inpx[train, ], inpy[train], alpha = 1)
lasso.fit <- glmnet(inpx[train, ], inpy[train], alpha = 1, lambda = cv.out$lambda.min)
lasso.pred <- predict(lasso.fit, inpx[test, ], s = cv.out$lambda.min)
mean((lasso.pred - inpy[test]) ^ 2)
[1] 1034786
coef(lasso.fit, 20)
18 x 1 sparse Matrix of class "dgCMatrix"
                        1
(Intercept) -3.674800e+02
PrivateYes  -5.305394e+02
Accept       1.556370e+00
Enroll      -4.041862e-01
Top10perc    5.032803e+01
Top25perc   -9.825451e+00
F.Undergrad -1.798594e-02
P.Undergrad  .           
Outstate    -5.752475e-02
Room.Board   1.963418e-01
Books        1.927387e-02
Personal     3.556498e-03
PhD         -4.740559e+00
Terminal    -2.924054e+00
S.F.Ratio    .           
perc.alumni -2.264210e+00
Expend       3.257759e-02
Grad.Rate    3.412244e+00
# predict(lasso.fit, type = 'coefficients', s = cv.out$lambda.min) product same results with above `coef` function

2 (P.Undergrad and S. F. Ratio) of 17 predictors are zeros.

(e): fit with PCR and calculate the test error:

library(pls)
set.seed(1)
pcr.fit <- pcr(Apps ~ ., data = College, subset = train, scale = TRUE, validation = 'CV')
summary(pcr.fit)
Data:   X dimension: 388 17 
    Y dimension: 388 1
Fit method: svdpc
Number of components considered: 17

VALIDATION: RMSEP
Cross-validated using 10 random segments.
       (Intercept)  1 comps  2 comps  3 comps  4 comps  5 comps  6 comps  7 comps
CV            4335     4179     2364     2374     1996     1844     1845     1850
adjCV         4335     4182     2360     2374     1788     1831     1838     1844
       8 comps  9 comps  10 comps  11 comps  12 comps  13 comps  14 comps  15 comps
CV        1863     1809      1809      1812      1815      1825      1810      1823
adjCV     1857     1801      1800      1804      1808      1817      1806      1789
       16 comps  17 comps
CV         1273      1281
adjCV      1260      1268

TRAINING: % variance explained
      1 comps  2 comps  3 comps  4 comps  5 comps  6 comps  7 comps  8 comps  9 comps
X      31.216    57.68    64.73    70.55    76.33    81.30    85.01    88.40    91.16
Apps    6.976    71.47    71.58    83.32    83.44    83.45    83.46    83.47    84.53
      10 comps  11 comps  12 comps  13 comps  14 comps  15 comps  16 comps  17 comps
X        93.36     95.38     96.94     97.96     98.76     99.40     99.87    100.00
Apps     84.86     84.98     84.98     84.99     85.24     90.87     93.93     93.97
validationplot(pcr.fit, val.type = 'MSEP')

pcr.pred <- predict(pcr.fit, inpx[test, ], ncomp = 5)
mean((pcr.pred - inpy[test]) ^ 2)
[1] 1907827

When \(M=5\), the test MSE is 1907827.

(f): fit with PLS and calculate the test error:

library(pls)
set.seed(1)
pls.fit <- plsr(Apps ~ ., data = College, subset = train, scale = TRUE, validation = 'CV')
validationplot(pls.fit, val.type = 'MSEP')

pls.pred <- predict(pls.fit, inpx[test, ], ncomp = 6)
mean((pls.pred - inpy[test]) ^ 2)
[1] 1112189

When \(M=6\), the test MSE is 1112189.

(g): Compare the prediction accuracy with test \(R^2\) of above models:

test.avg.apps <- mean(inpy[test])
lr.r2 <- 1 - mean((lr.pred - inpy[test])^2) / mean((test.avg.apps - inpy[test])^2)
rr.r2 <- 1 - mean((rr.pred - inpy[test])^2) / mean((test.avg.apps - inpy[test])^2)
lasso.r2 <- 1 - mean((lasso.pred - inpy[test])^2) / mean((test.avg.apps - inpy[test])^2)
prc.r2 <- 1 - mean((pcr.pred - inpy[test])^2) / mean((test.avg.apps - inpy[test])^2)
pls.r2 <- 1 - mean((pls.pred - inpy[test])^2) / mean((test.avg.apps - inpy[test])^2)
barplot(c(lr.r2, rr.r2, lasso.r2, pcr.r2, pls.r2), col="gray", names.arg=c("LR", "Ridge", "Lasso", "PCR", "PLS"), main="Test R-squared")

For this data set, linear regression is the most accurate, while PCR give the worst prediction accuracy.

LS0tCnRpdGxlOiAiQXBwbGllZCBFeGVyY2lzZXMgb2YgQ2hhcHRlciA2IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFF1ZXN0aW9uIDgKCkdlbmVyYXRlIHRlc3QgZGF0YToKYGBge3J9CmxpYnJhcnkoSVNMUikKc2V0LnNlZWQoMSkKeCA8LSBybm9ybSgxMDApCmVwcyA8LSBybm9ybSgxMDApCmJldGEwIDwtIDIuNzMxCmJldGExIDwtIC0zLjI5NgpiZXRhMiA8LSA1LjExNwpiZXRhMyA8LSAtMS43OTMKeSA8LSBiZXRhMCArIGJldGExICogeCArIGJldGEyICogeF4yICsgYmV0YTMgKiB4XjMgKyBlcHMKcGxvdCh4LCB5KQppbnAgPC0gZGF0YS5mcmFtZSh4LCB5KQpgYGAKCiMjIChjKSBGaXQgd2l0aCBiZXN0IHN1YnNldHMgc2VsZWN0aW9uCmBgYHtyfQpic3MgPC0gcmVnc3Vic2V0cyh5IH4geCArIEkoeF4yKSArIEkoeF4zKSArIEkoeF40KSArIEkoeF41KSArIEkoeF42KSArIEkoeF43KSArIEkoeF44KSArIEkoeF45KSArIEkoeF4xMCksIGRhdGEgPSBpbnAsIG52bWF4ID0gMTApCmJzcy5zdW1tYXJ5IDwtIHN1bW1hcnkoYnNzKQpic3Muc3VtbWFyeQoKcGFyKG1mcm93PWMoMSwzKSkKcGxvdChic3Muc3VtbWFyeSRhZGpyMiwgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdBZGp1c3RlZCBSMicsIHR5cGUgPSAnbCcpCnJzcS5tYXguaWR4IDwtIHdoaWNoLm1heChic3Muc3VtbWFyeSRhZGpyMikKcG9pbnRzKHJzcS5tYXguaWR4LCBic3Muc3VtbWFyeSRhZGpyMltyc3EubWF4LmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKCmNwLm1pbi5pZHggPC0gd2hpY2gubWluKGJzcy5zdW1tYXJ5JGNwKQpwbG90KGJzcy5zdW1tYXJ5JGNwLCB4bGFiID0gJ051bWJlciBvZiB2YXJpYWJsZXMnLCB5bGFiID0gJ0NwJywgdHlwZSA9ICdsJykKcG9pbnRzKGNwLm1pbi5pZHgsIGJzcy5zdW1tYXJ5JGNwW2NwLm1pbi5pZHhdLCBjb2wgPSAncmVkJywgY2V4ID0gMiwgcGNoID0gMjApCgpiaWMubWluLmlkeCA8LSB3aGljaC5taW4oYnNzLnN1bW1hcnkkYmljKQpwbG90KGJzcy5zdW1tYXJ5JGJpYywgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdCSUMnLCB0eXBlID0gJ2wnKQpwb2ludHMoYmljLm1pbi5pZHgsIGJzcy5zdW1tYXJ5JGJpY1tiaWMubWluLmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoYnNzLCBzY2FsZSA9ICdhZGpyMicpCnBsb3QoYnNzLCBzY2FsZSA9ICdDcCcpCnBsb3QoYnNzLCBzY2FsZSA9ICdiaWMnKQpgYGAKQWNjb3JkaW5nIHRvIGFkanVzdGVkICRSXjIkIGFuZCAkQ19wJCwgdGhlIGJlc3QgbW9kZWwgY29udGFpbnMgNCBwcmVkaWN0b3JzOiAkWCQsICRYXjIkLCAkWF4zJCBhbmQgJFheNSQuCkFjY29yZGluZyB0byBCSUMsIHRoZSBiZXN0IG1vZGVsIGNvbnRhaW5zIDMgcHJlZGljdG9yczogJFgkLCAkWF4yJCBhbmQgJFheMyQuCgpHZXQgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlczoKYGBge3J9CmNvZWYoYnNzLCAzKQpgYGAKVGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcyB2cyBvcmlnaW4gY29lZmZpY2llbnRzOgokJApcYmV0YV8wID0gMi43MzEgXHF1YWQgXGJldGFfMSA9IC0zLjI5NiBccXVhZCBcYmV0YV8yID0gNS4xMTcgXHF1YWQgXGJldGFfMyA9IC0xLjc5M1xcClxoYXRcYmV0YV8wID0gMi43OTMgXHF1YWQgXGhhdFxiZXRhXzEgPSAtMy4zMjEgXHF1YWQgXGhhdFxiZXRhXzIgPSA0Ljk5M1xxdWFkIFxoYXRcYmV0YV8zID0gLTEuNzc1CiQkCgojIyAoZCkKRml0IHdpdGggZm9yd2FyZCBzdGVwd2lzZSBzZWxlY3Rpb24gbWV0aG9kOgpgYGB7cn0KZnNzIDwtIHJlZ3N1YnNldHMoeSB+IHggKyBJKHheMikgKyBJKHheMykgKyBJKHheNCkgKyBJKHheNSkgKyBJKHheNikgKyBJKHheNykgKyBJKHheOCkgKyBJKHheOSkgKyBJKHheMTApLCBkYXRhID0gaW5wLCBtZXRob2QgPSAnZm9yd2FyZCcsIG52bWF4ID0gMTApCmZzcy5zdW1tYXJ5IDwtIHN1bW1hcnkoZnNzKQpmc3Muc3VtbWFyeQoKcGFyKG1mcm93PWMoMSwzKSkKcGxvdChmc3Muc3VtbWFyeSRhZGpyMiwgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdBZGp1c3RlZCBSMicsIHR5cGUgPSAnbCcpCnJzcS5tYXguaWR4IDwtIHdoaWNoLm1heChmc3Muc3VtbWFyeSRhZGpyMikKcG9pbnRzKHJzcS5tYXguaWR4LCBmc3Muc3VtbWFyeSRhZGpyMltyc3EubWF4LmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKCmNwLm1pbi5pZHggPC0gd2hpY2gubWluKGZzcy5zdW1tYXJ5JGNwKQpwbG90KGZzcy5zdW1tYXJ5JGNwLCB4bGFiID0gJ051bWJlciBvZiB2YXJpYWJsZXMnLCB5bGFiID0gJ0NwJywgdHlwZSA9ICdsJykKcG9pbnRzKGNwLm1pbi5pZHgsIGZzcy5zdW1tYXJ5JGNwW2NwLm1pbi5pZHhdLCBjb2wgPSAncmVkJywgY2V4ID0gMiwgcGNoID0gMjApCgpiaWMubWluLmlkeCA8LSB3aGljaC5taW4oZnNzLnN1bW1hcnkkYmljKQpwbG90KGZzcy5zdW1tYXJ5JGJpYywgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdCSUMnLCB0eXBlID0gJ2wnKQpwb2ludHMoYmljLm1pbi5pZHgsIGZzcy5zdW1tYXJ5JGJpY1tiaWMubWluLmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKYGBgCkFjY29yZGluZyB0byBhZGp1c3RlZCAkUl4yJCwgdGhlIGJlc3QgbW9kZWwgY29udGFpbnMgNSBwcmVkaWN0b3JzOiAkWCQgfiAkWF41JC4KQWNjb3JkaW5nIHRvICRDX3AkLCB0aGUgYmVzdCBtb2RlbCBjb250YWlucyA0IHByZWRpY3RvcnM6ICRYJCwgJFheMiQsICRYXjMkIGFuZCAkWF41JC4KQWNjb3JkaW5nIHRvIEJJQywgdGhlIGJlc3QgbW9kZWwgY29udGFpbnMgMyBwcmVkaWN0b3JzOiAkWCQsICRYXjIkIGFuZCAkWF4zJC4KCkZpdCB3aXRoIGJhY2t3YXJkIHN0ZXB3aXNlIHNlbGVjdGlvbiBtZXRob2Q6CmBgYHtyfQpia3MgPC0gcmVnc3Vic2V0cyh5IH4geCArIEkoeF4yKSArIEkoeF4zKSArIEkoeF40KSArIEkoeF41KSArIEkoeF42KSArIEkoeF43KSArIEkoeF44KSArIEkoeF45KSArIEkoeF4xMCksIGRhdGEgPSBpbnAsIG1ldGhvZCA9ICdiYWNrd2FyZCcsIG52bWF4ID0gMTApCmJrcy5zdW1tYXJ5IDwtIHN1bW1hcnkoYmtzKQpia3Muc3VtbWFyeQoKd2hpY2gubWF4KGJrcy5zdW1tYXJ5JGFkanIyKQp3aGljaC5taW4oYmtzLnN1bW1hcnkkY3ApCmJrcy5zdW1tYXJ5JGJpYwp3aGljaC5taW4oYmtzLnN1bW1hcnkkYmljKQoKcGFyKG1mcm93PWMoMSwzKSkKcGxvdChia3Muc3VtbWFyeSRhZGpyMiwgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdBZGp1c3RlZCBSMicsIHR5cGUgPSAnbCcpCnJzcS5tYXguaWR4IDwtIHdoaWNoLm1heChia3Muc3VtbWFyeSRhZGpyMikKcG9pbnRzKHJzcS5tYXguaWR4LCBia3Muc3VtbWFyeSRhZGpyMltyc3EubWF4LmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKCmNwLm1pbi5pZHggPC0gd2hpY2gubWluKGJrcy5zdW1tYXJ5JGNwKQpwbG90KGJrcy5zdW1tYXJ5JGNwLCB4bGFiID0gJ051bWJlciBvZiB2YXJpYWJsZXMnLCB5bGFiID0gJ0NwJywgdHlwZSA9ICdsJykKcG9pbnRzKGNwLm1pbi5pZHgsIGJrcy5zdW1tYXJ5JGNwW2NwLm1pbi5pZHhdLCBjb2wgPSAncmVkJywgY2V4ID0gMiwgcGNoID0gMjApCgpiaWMubWluLmlkeCA8LSB3aGljaC5taW4oYmtzLnN1bW1hcnkkYmljKQpwbG90KGJrcy5zdW1tYXJ5JGJpYywgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdCSUMnLCB0eXBlID0gJ2wnKQpwb2ludHMoYmljLm1pbi5pZHgsIGJrcy5zdW1tYXJ5JGJpY1tiaWMubWluLmlkeF0sIGNvbCA9ICdyZWQnLCBjZXggPSAyLCBwY2ggPSAyMCkKYGBgClRoZSByZXN1bHQgaXMgdGhlIHNhbWUgd2l0aCBmb3J3YXJkIHN0ZXB3aXNlIHNlbGVjdGlvbiBtZXRob2RzLgpUaGUgcmVzdWx0cyBvZiBmb3J3YXJkL2JhY2t3YXJkIHN0ZXB3aXNlIHNlbGVjdGlvbiBhcmUgYmFzaWNhbGx5IHRoZSBzYW1lIHdpdGggcmVzdWx0cyBvZiBiZXN0IHN1YnNldHMgbWV0aG9kcy4KCkdldCB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzICh3aGljaCBpcyB0aGUgc2FtZSB3aXRoIHJlc3VsdHMgb2YgYmVzdCBzdWJzZXRzIG1ldGhvZCBpbiBzZWN0aW9uIChjKSk6CmBgYHtyfQpjb2VmKGZzcywgMykKY29lZihia3MsIDMpCmBgYAoKIyMjIFVzZSBgSSgpYCBpbnN0ZWFkIG9mIGBwb2x5YApgYGB7cn0KZnNzLnBvbHkgPC0gcmVnc3Vic2V0cyh5IH4gcG9seSh4LCAxMCksIGRhdGEgPSBpbnAsIG1ldGhvZCA9ICdmb3J3YXJkJywgbnZtYXggPSAxMCkKY29lZihmc3MucG9seSwgMykKYGBgClNvIHRoZSB3cm9uZyBjb2VmZmljaWVudCBlc3RpbWF0ZXMgc2hvdyB0aGUgYHBvbHkoeCwgMTApYCBpcyB3cm9uZyBoZXJlLgoKIyMgKGUpCkZpdCB3aXRoIGxhc3NvIG1vZGVsOgpgYGB7cn0KWCA8LSBkYXRhLmZyYW1lKHgsIHheMiwgeF4zLCB4XjQsIHheNSwgeF42LCB4XjcsIHheOCwgeF45LCB4XjEwKQpsYXNzby5jdiA8LSBjdi5nbG1uZXQoYXMubWF0cml4KFgpLCB5LCBhbHBoYSA9IDEpCnBsb3QobGFzc28uY3YpCmxibCA8LSBsYXNzby5jdiRsYW1iZGEubWluCmxhc3NvLnJlcyA8LSBnbG1uZXQoYXMubWF0cml4KFgpLCB5LCBhbHBoYSA9IDEsIGxhbWJkYSA9IGxibCkKbGFzc28ucmVzJGJldGEKbGFzc28ucmVzJGEwCmBgYApUaGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIHZzIG9yaWdpbiBjb2VmZmljaWVudHM6CiQkClxiZXRhXzAgPSAyLjczMSBccXVhZCBcYmV0YV8xID0gLTMuMjk2IFxxdWFkIFxiZXRhXzIgPSA1LjExNyBccXVhZCBcYmV0YV8zID0gLTEuNzkzXFwKXGhhdFxiZXRhXzAgPSAyLjkwNiBccXVhZCBcaGF0XGJldGFfMSA9IC0zLjI1MCBccXVhZCBcaGF0XGJldGFfMiA9IDQuNzE5IFxxdWFkIFxoYXRcYmV0YV8zID0gLTEuNzg2CiQkCgojIyAoZikKCkZpdCAkWSA9IFxiZXRhXzAgKyBcYmV0YV83IFheNyArIFxlcHNpbG9uJCB3aXRoIGJlc3Qgc3Vic2V0cyBtZXRob2Q6CmBgYHtyfQpiZXRhNyA8LSA3LjY5Nwp5ZiA8LSBiZXRhMCArIGJldGE3ICogeF43ICsgZXBzCgpic2YgPC0gcmVnc3Vic2V0cyh5ZiB+IHggKyBJKHheMikgKyBJKHheMykgKyBJKHheNCkgKyBJKHheNSkgKyBJKHheNikgKyBJKHheNykgKyBJKHheOCkgKyBJKHheOSkgKyBJKHheMTApLCBkYXRhID0gaW5wLCBudm1heCA9IDEwKQpic2Yuc3VtbWFyeSA8LSBzdW1tYXJ5KGJzZikKYnNmLnN1bW1hcnkKCnBhcihtZnJvdz1jKDEsMykpCnBsb3QoYnNmLnN1bW1hcnkkYWRqcjIsIHhsYWIgPSAnTnVtYmVyIG9mIHZhcmlhYmxlcycsIHlsYWIgPSAnQWRqdXN0ZWQgUjInLCB0eXBlID0gJ2wnKQpyc3EubWF4LmlkeCA8LSB3aGljaC5tYXgoYnNmLnN1bW1hcnkkYWRqcjIpCnBvaW50cyhyc3EubWF4LmlkeCwgYnNmLnN1bW1hcnkkYWRqcjJbcnNxLm1heC5pZHhdLCBjb2wgPSAncmVkJywgY2V4ID0gMiwgcGNoID0gMjApCgpjcC5taW4uaWR4IDwtIHdoaWNoLm1pbihic2Yuc3VtbWFyeSRjcCkKcGxvdChic2Yuc3VtbWFyeSRjcCwgeGxhYiA9ICdOdW1iZXIgb2YgdmFyaWFibGVzJywgeWxhYiA9ICdDcCcsIHR5cGUgPSAnbCcpCnBvaW50cyhjcC5taW4uaWR4LCBic2Yuc3VtbWFyeSRjcFtjcC5taW4uaWR4XSwgY29sID0gJ3JlZCcsIGNleCA9IDIsIHBjaCA9IDIwKQoKYmljLm1pbi5pZHggPC0gd2hpY2gubWluKGJzZi5zdW1tYXJ5JGJpYykKcGxvdChic2Yuc3VtbWFyeSRiaWMsIHhsYWIgPSAnTnVtYmVyIG9mIHZhcmlhYmxlcycsIHlsYWIgPSAnQklDJywgdHlwZSA9ICdsJykKcG9pbnRzKGJpYy5taW4uaWR4LCBic2Yuc3VtbWFyeSRiaWNbYmljLm1pbi5pZHhdLCBjb2wgPSAncmVkJywgY2V4ID0gMiwgcGNoID0gMjApCmBgYAoKQ29tcGFyZSB0aGUgY29lZmZpY2llbnRzOgpgYGB7cn0KY29lZihic2YsIDEpCmBgYApUaGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIHZzIG9yaWdpbiBjb2VmZmljaWVudHM6CiQkClxiZXRhXzAgPSAyLjczMSBccXVhZCBcYmV0YV83ID0gNy42OTcgXFwKXGhhdFxiZXRhXzAgPSAyLjY5MCBccXVhZCBcaGF0XGJldGFfMSA9IDcuNjk4CiQkCgpGaXQgd2l0aCBsYXNzbzoKYGBge3J9ClggPC0gZGF0YS5mcmFtZSh4LCB4XjIsIHheMywgeF40LCB4XjUsIHheNiwgeF43LCB4XjgsIHheOSwgeF4xMCkKbGFzc28uY3YgPC0gY3YuZ2xtbmV0KGFzLm1hdHJpeChYKSwgeWYsIGFscGhhID0gMSkKcGxvdChsYXNzby5jdikKbGJsIDwtIGxhc3NvLmN2JGxhbWJkYS5taW4KbGFzc28ucmVzIDwtIGdsbW5ldChhcy5tYXRyaXgoWCksIHlmLCBhbHBoYSA9IDEsIGxhbWJkYSA9IGxibCkKbGFzc28ucmVzJGJldGEKbGFzc28ucmVzJGEwCmBgYApUaGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIHZzIG9yaWdpbiBjb2VmZmljaWVudHM6CiQkClxiZXRhXzAgPSAyLjczMSBccXVhZCBcYmV0YV83ID0gNy42OTcgXFwKXGhhdFxiZXRhXzAgPSAzLjczNCBccXVhZCBcaGF0XGJldGFfMSA9IDcuNDM2CiQkClNvIGZvciB0aGlzIG1vZGVsLCB0aGUgbGFzc28gZ2l2ZSB3b3JzZSBjb2VmZmljaWVudHMgdGhhbiBiZXN0IHN1YnNldHMuCgojIFF1ZXN0aW9uIDkKCihhKSBhbmQgKGIpOiBnZW5lcmF0ZSBkYXRhIHNldCwgZml0IHdpdGggbGluZWFyIHJlZ3Jlc3Npb24gYW5kIGNhbGN1bGF0ZSB0ZXN0IGVycm9yOgpgYGB7cn0Kc2V0LnNlZWQoMSkKdHJhaW4gPC0gc2FtcGxlKDE6IG5yb3coQ29sbGVnZSksIG5yb3coQ29sbGVnZSkvMikKdGVzdCA8LSAtdHJhaW4KbHIuZml0IDwtIGxtKEFwcHMgfiAuLCBkYXRhID0gQ29sbGVnZSkKbHIucHJlZCA8LSBwcmVkaWN0KGxyLmZpdCwgQ29sbGVnZVt0ZXN0LCBdKQptZWFuKChsci5wcmVkIC0gQ29sbGVnZVt0ZXN0LCBdJEFwcHMpIF4gMikKc3VtbWFyeShsci5maXQpCmBgYAoKKGMpOiBmaXQgd2l0aCByaWRnZSByZWdyZXNzaW9uIGFuZCBjYWxjdWxhdGUgdGVzdCBlcnJvcjoKYGBge3J9CnNldC5zZWVkKDEpCmlucHggPC0gbW9kZWwubWF0cml4KEFwcHMgfiAuLCBkYXRhID0gQ29sbGVnZSlbLCAtMV0KaW5weSA8LSBDb2xsZWdlJEFwcHMKY3Yub3V0IDwtIGN2LmdsbW5ldChpbnB4W3RyYWluLCBdLCBpbnB5W3RyYWluXSwgYWxwaGEgPSAwKQpyci5maXQgPC0gZ2xtbmV0KGlucHhbdHJhaW4sIF0sIGlucHlbdHJhaW5dLCBhbHBoYSA9IDAsIGxhbWJkYSA9IGN2Lm91dCRsYW1iZGEubWluKQpyci5wcmVkIDwtIHByZWRpY3QocnIuZml0LCBpbnB4W3Rlc3QsIF0sIHMgPSBjdi5vdXQkbGFtYmRhLm1pbikKbWVhbigocnIucHJlZCAtIGlucHlbdGVzdF0pIF4gMikKYGBgCgooZCk6IGZpdCB3aXRoIGxhc3NvLCBjYWxjdWxhdGUgdGhlIHRlc3QgZXJyb3IgYW5kIHNob3cgY29lZmZpY2llbnQgZXN0aW1hdGVzOgpgYGB7cn0Kc2V0LnNlZWQoMSkKY3Yub3V0IDwtIGN2LmdsbW5ldChpbnB4W3RyYWluLCBdLCBpbnB5W3RyYWluXSwgYWxwaGEgPSAxKQpsYXNzby5maXQgPC0gZ2xtbmV0KGlucHhbdHJhaW4sIF0sIGlucHlbdHJhaW5dLCBhbHBoYSA9IDEsIGxhbWJkYSA9IGN2Lm91dCRsYW1iZGEubWluKQpsYXNzby5wcmVkIDwtIHByZWRpY3QobGFzc28uZml0LCBpbnB4W3Rlc3QsIF0sIHMgPSBjdi5vdXQkbGFtYmRhLm1pbikKbWVhbigobGFzc28ucHJlZCAtIGlucHlbdGVzdF0pIF4gMikKY29lZihsYXNzby5maXQsIDIwKQojIHByZWRpY3QobGFzc28uZml0LCB0eXBlID0gJ2NvZWZmaWNpZW50cycsIHMgPSBjdi5vdXQkbGFtYmRhLm1pbikgcHJvZHVjdCBzYW1lIHJlc3VsdHMgd2l0aCBhYm92ZSBgY29lZmAgZnVuY3Rpb24KYGBgCgoyICgqUC5VbmRlcmdyYWQqIGFuZCAqUy4gRi4gUmF0aW8qKSBvZiAxNyBwcmVkaWN0b3JzIGFyZSB6ZXJvcy4KCihlKTogZml0IHdpdGggUENSIGFuZCBjYWxjdWxhdGUgdGhlIHRlc3QgZXJyb3I6CmBgYHtyfQpsaWJyYXJ5KHBscykKc2V0LnNlZWQoMSkKcGNyLmZpdCA8LSBwY3IoQXBwcyB+IC4sIGRhdGEgPSBDb2xsZWdlLCBzdWJzZXQgPSB0cmFpbiwgc2NhbGUgPSBUUlVFLCB2YWxpZGF0aW9uID0gJ0NWJykKc3VtbWFyeShwY3IuZml0KQp2YWxpZGF0aW9ucGxvdChwY3IuZml0LCB2YWwudHlwZSA9ICdNU0VQJykKcGNyLnByZWQgPC0gcHJlZGljdChwY3IuZml0LCBpbnB4W3Rlc3QsIF0sIG5jb21wID0gNSkKbWVhbigocGNyLnByZWQgLSBpbnB5W3Rlc3RdKSBeIDIpCmBgYApXaGVuICRNPTUkLCB0aGUgdGVzdCBNU0UgaXMgMTkwNzgyNy4KCihmKTogZml0IHdpdGggUExTIGFuZCBjYWxjdWxhdGUgdGhlIHRlc3QgZXJyb3I6CmBgYHtyfQpsaWJyYXJ5KHBscykKc2V0LnNlZWQoMSkKcGxzLmZpdCA8LSBwbHNyKEFwcHMgfiAuLCBkYXRhID0gQ29sbGVnZSwgc3Vic2V0ID0gdHJhaW4sIHNjYWxlID0gVFJVRSwgdmFsaWRhdGlvbiA9ICdDVicpCnZhbGlkYXRpb25wbG90KHBscy5maXQsIHZhbC50eXBlID0gJ01TRVAnKQpwbHMucHJlZCA8LSBwcmVkaWN0KHBscy5maXQsIGlucHhbdGVzdCwgXSwgbmNvbXAgPSA2KQptZWFuKChwbHMucHJlZCAtIGlucHlbdGVzdF0pIF4gMikKYGBgCldoZW4gJE09NiQsIHRoZSB0ZXN0IE1TRSBpcyAxMTEyMTg5LgoKKGcpOiBDb21wYXJlIHRoZSBwcmVkaWN0aW9uIGFjY3VyYWN5IHdpdGggdGVzdCAkUl4yJCBvZiBhYm92ZSBtb2RlbHM6CmBgYHtyfQp0ZXN0LmF2Zy5hcHBzIDwtIG1lYW4oaW5weVt0ZXN0XSkKCmxyLnIyIDwtIDEgLSBtZWFuKChsci5wcmVkIC0gaW5weVt0ZXN0XSleMikgLyBtZWFuKCh0ZXN0LmF2Zy5hcHBzIC0gaW5weVt0ZXN0XSleMikKCnJyLnIyIDwtIDEgLSBtZWFuKChyci5wcmVkIC0gaW5weVt0ZXN0XSleMikgLyBtZWFuKCh0ZXN0LmF2Zy5hcHBzIC0gaW5weVt0ZXN0XSleMikKCmxhc3NvLnIyIDwtIDEgLSBtZWFuKChsYXNzby5wcmVkIC0gaW5weVt0ZXN0XSleMikgLyBtZWFuKCh0ZXN0LmF2Zy5hcHBzIC0gaW5weVt0ZXN0XSleMikKCnByYy5yMiA8LSAxIC0gbWVhbigocGNyLnByZWQgLSBpbnB5W3Rlc3RdKV4yKSAvIG1lYW4oKHRlc3QuYXZnLmFwcHMgLSBpbnB5W3Rlc3RdKV4yKQpwbHMucjIgPC0gMSAtIG1lYW4oKHBscy5wcmVkIC0gaW5weVt0ZXN0XSleMikgLyBtZWFuKCh0ZXN0LmF2Zy5hcHBzIC0gaW5weVt0ZXN0XSleMikKCmJhcnBsb3QoYyhsci5yMiwgcnIucjIsIGxhc3NvLnIyLCBwY3IucjIsIHBscy5yMiksIGNvbD0iZ3JheSIsIG5hbWVzLmFyZz1jKCJMUiIsICJSaWRnZSIsICJMYXNzbyIsICJQQ1IiLCAiUExTIiksIG1haW49IlRlc3QgUi1zcXVhcmVkIikKYGBgCkZvciB0aGlzIGRhdGEgc2V0LCBsaW5lYXIgcmVncmVzc2lvbiBpcyB0aGUgbW9zdCBhY2N1cmF0ZSwgd2hpbGUgUENSIGdpdmUgdGhlIHdvcnN0IHByZWRpY3Rpb24gYWNjdXJhY3kuCg==