4.4: Un ejemplo del proceso de eliminación hacia atrás
- Page ID
- 149811
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
Anteriormente identificamos la lista de posibles predictores que podemos incluir en nuestros modelos, que se muestra en la Tabla 4.1. Comenzamos el proceso de eliminación hacia atrás poniendo todos estos predictores potenciales en un modelo para el marco de datos int00.dat
usando la función lm ()
.
> int00.lm <lm(nperf ~ clock + threads + cores + transistors +
dieSize + voltage + featureSize + channel + FO4delay + L1icache +
sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache),
data=int00.dat)
Esta llamada a la función asigna el objeto de modelo lineal resultante a la variable int00.lm
. Como antes, usamos el sufijo .lm
para recordarnos que esta variable es un modelo lineal desarrollado a partir de los datos en el marco de datos correspondiente, int00.dat
. Los argumentos en la llamada a la función le dicen a lm ()
que calme un modelo lineal que explique la salida nperf
en función de los predictores separados por los signos “+”. El argumento data=int00.dat
pasa explícitamente a la función lm ()
el nombre del marco de datos que se debe usar al desarrollar este modelo. Este argumento data=
no es necesario si adjuntamos ()
el marco de datos int00.dat
al espacio de trabajo actual. Sin embargo, es útil especificar explícitamente el marco de datos que lm ()
debe usar, para evitar confusiones cuando manipula múltiples modelos simultáneamente.
La función summary ()
nos da una gran cantidad de información sobre el modelo lineal que acabamos de crear:
> summary(int00.lm) Call: lm(formula = nperf ~ clock + threads + cores + transistors + dieSize + voltage + featureSize + channel + FO4delay + L1icache + sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat) Residuals:
Min 1Q Median 3Q Max -10.804 -2.702 0.000 2.285 9.809 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -2.108e+01 7.852e+01 -0.268 0.78927 clock 2.605e-02 1.671e-03 15.594 < 2e-16 *** threads -2.346e+00 2.089e+00 -1.123 0.26596 cores 2.246e+00 1.782e+00 1.260 0.21235 transistors -5.580e-03 1.388e-02 -0.402 0.68897 dieSize 1.021e-02 1.746e-02 0.585 0.56084 voltage -2.623e+01 7.698e+00 -3.408 0.00117 ** freatureSize 3.101e+01 1.122e+02 0.276 0.78324 channel 9.496e+01 5.945e+02 0.160 0.87361 FO4delay -1.765e-02 1.600e+00 -0.011 0.99123 L1icache 1.102e+02 4.206e+01 2.619 0.01111 * sqrt(L1icache) -7.390e+02 2.980e+02 -2.480 0.01593 * L1dcache -1.114e+02 4.019e+01 -2.771 0.00739 ** sqrt(L1dcache) 7.492e+02 2.739e+02 2.735 0.00815 ** L2cache -9.684e-03 1.745e-03 -5.550 6.57e-07 *** sqrt(L2cache) 1.221e+00 2.425e-01 5.034 4.54e-06 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 4.632 on 61 degrees of freedom (179 observations deleted due to missingness) Multiple R-squared: 0.9652, Adjusted R-squared: 0.9566 F-statistic: 112.8 on 15 and 61 DF, p-value: < 2.2e-16
Observe algunas cosas en este resumen: Primero, un rápido vistazo a los residuales muestra que están aproximadamente equilibrados alrededor de una mediana de cero, que es lo que nos gusta ver en nuestros modelos. También, fíjese en la línea, (179 observaciones eliminadas por falta de identidad
). Esto nos dice que en 179 de las filas del marco de datos es decir, en 179 de los procesadores para los que se reportaron resultados de desempeño para el benchmark Int2000 faltaban algunos de los valores en las columnas que nos gustaría usar como posibles predictores. Estos valores de NA provocaron que R eliminara automáticamente estas filas de datos al calcular el modelo lineal.
El número total de observaciones utilizadas en el modelo es igual al número de grados de libertad restantes 61 en este caso más el número total de predictores en el modelo. Por último, observe que los valores de R2 y R2 ajustados son relativamente cercanos a uno, lo que indica que el modelo explica bien los valores de nperf
. Recordemos, sin embargo, que estos grandes valores de R2 pueden simplemente mostrarnos que el modelo es bueno para modelar el ruido en las mediciones. Aún debemos determinar si debemos retener todos estos predictores potenciales en el modelo.
Para continuar desarrollando el modelo, aplicamos el procedimiento de eliminación hacia atrás identificando el predictor con el mayor valor p que excede nuestro umbral predeterminado de p = 0.05. Este predictor es Fo4Delay
, que tiene un valor p de 0.99123. Podemos usar la función update ()
para eliminar un predictor dado y volver a calcular el modelo en un solo paso. La notación “.~.” significa que update ()
debe mantener los lados izquierdo y derecho del modelo iguales. Al incluir “- Fo4Delay
”, también le decimos que elimine ese predictor del modelo, como se muestra en lo siguiente:
> int00.lm <- update(int00.lm, .~. - FO4delay, data = int00.dat) > summary(int00.lm) Call: lm(formula = nperf ~ clock + threads + cores + transistors + dieSize + voltage + featureSize + channel + L1icache + sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat) Residuals:
Min 1Q Median 3Q Max -10.795 -2.714 0.000 2.283 9.809 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -2.088e+01 7.584e+01 -0.275 0.783983 clock 2.604e-02 1.563e-03 16.662 < 2e-16 *** threads -2.345e+00 2.070e+00 -1.133 0.261641 cores 2.248e+00 1.759e+00 1.278 0.206080 transistors -5.556e-03 1.359e-02 -0.409 0.684020 dieSize 1.013e-02 1.571e-02 0.645 0.521488 voltage -2.626e+01 7.302e+00 -3.596 0.000642 *** featureSize 3.104e+01 1.113e+02 0.279 0.781232 channel 8.855e+01 1.218e+02 0.727 0.469815 L1icache 1.103e+02 4.041e+01 2.729 0.008257 ** sqrt(L1icache) -7.398e+02 2.866e+02 -2.581 0.012230 * L1dcache -1.115e+02 3.859e+01 -2.889 0.005311 **
sqrt(L1dcache) 7.500e+02 2.632e+02 2.849 0.005937 ** L2cache -9.693e-03 1.494e-01 -6.488 1.64e-08 *** sqrt(L2cache) 1.222e+00 1.975e-01 6.189 5.33e-08 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 4.594 on 62 degrees of freedom (179 observations deleted due to missingness) Multiple R-squared: 0.9652, Adjusted R-squared: 0.9573 F-statistic: 122.8 on 14 and 62 DF, p-value: < 2.2e-16
Repetimos este proceso eliminando el siguiente predictor potencial con el mayor valor p que excede nuestro umbral predeterminado, FeatureSize
. Al repetir este proceso, obtenemos la siguiente secuencia de posibles modelos.
Eliminar FeatureSize
:
> int00.lm <- update(int00.lm, .~. - featureSize, data=int00.dat) > summary(int00.lm) Call: lm(formula = nperf ~ clock + threads + cores + transistors + dieSize + voltage + channel + L1icache + sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat) Residuals:
Min 1Q Median 3Q Max -10.5548 -2.6442 0.0937 2.2010 10.0264 Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) -3.129e+01 6.554e+01 -0.477 0.634666 clock 2.591e-02 1.471e-03 17.609 < 2e-16 *** threads -2.447e+00 2.022e+00 -1.210 0.230755 cores 1.901e+00 1.233e+00 1.541 0.128305 transistors -5.366e-03 1.347e-02 -0.398 0.691700 dieSize 1.325e-02 1.097e-02 1.208 0.231608 voltage -2.519e+01 6.182e+00 -4.075 0.000131 *** channel 1.188e+02 5.504e+01 2.158 0.034735 * L1icache 1.037e+02 3.255e+01 3.186 0.002246 ** sqrt(L1icache) -6.930e+02 2.307e+02 -3.004 0.003818 ** L1icache -1.052e+02 3.106e+01 -3.387 0.001223 ** sqrt(L1dcache) 7.069e+02 2.116e+02 3.341 0.001406 ** L2cache -9.548e-03 1.390e-03 -6.870 3.37e-09 *** sqrt(L2cache) 1.202e+00 1.821e-01 6.598 9.96e-09 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 4.56 on 63 degrees of freedom (179 observations deleted due to missingness) Multiple R-squared: 0.9651, Adjusted R-squared: 0.958 F-statistic: 134.2 on 13 and 63 DF, p-value: < 2.2e-16
Quitar transistores:
> int00.lm <- update(int00.lm, .~. - transistors, data=int00.dat) > summary(int00.lm) Call: lm(formula = nperf ~ clock + threads + cores + dieSize + voltage + channel + L1icache + sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat) Residuals:
Min 1Q Median 3Q Max -9.8861 -3.0801 -0.1871 2.4534 10.4863 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -7.789e+01 4.318e+01 -1.804 0.075745 . clock 2.566e-02 1.422e-03 18.040 < 2e-16 *** threads -1.801e+00 1.995e+00 -0.903 0.369794 cores 1.805e+00 1.132e+00 1.595 0.115496 dieSize 1.111e-02 8.807e-03 1.262 0.211407 voltage -2.379e+01 5.734e+00 -4.148 9.64e-05 *** channel 1.512e+02 3.918e+01 3.861 0.000257 *** L1icache 8.159e+01 2.006e+01 4.067 0.000128 *** sqrt(L1icache) -5.386e+02 1.418e+02 -3.798 0.000317 *** L1dcache -8.422e+01 1.914e+01 -4.401 3.96e-05 *** sqrt(L1dcache) 5.671e+02 1.299e+02 4.365 4.51e-05 *** L2cache -8.700e-03 1.262e-03 -6.893 2.35e-09 *** sqrt(L2cache) 1.069e+00 1.654e-01 6.465 1.36e-08 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 4.578 on 67 degrees of freedom (176 observations deleted due to missingness)
Multiple R-squared: 0.9657, Adjusted R-squared: 0.9596 F-statistic: 157.3 on 12 and 67 DF, p-value: < 2.2e-16
Quitar los hilos:
> int00.lm <- update(int00.lm, .~. - threads, data=int00.dat)
> summary(int00.lm)
Call:
lm(formula = nperf ~ clock + cores + dieSize + voltage + channel + L1icache +
sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat)
Residuals:
Min 1Q Median 3Q Max
-9.7388 -3.2326 0.1496 2.6633 10.6255
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -8.022e+01 4.304e+01 -1.864 0.066675 .
clock 2.552e-02 1.412e-03 18.074 <2e-16 ***
cores 2.271e+00 1.006e+00 2.257 0.027226 *
dieSize 1.281e-02 8.592e-03 1.491 0.140520
voltage -2.299e+01 5.657e+00 -4.063 0.000128 ***
channel 1.491e+02 3.905e+01 3.818 0.000293 ***
L1icache 8.131e+01 2.003e+01 4.059 0.000130 ***
sqrt(L1icache) -5.356e+02 1.416e+02 -3.783 0.000329 ***
L1dcache -8.388e+01 1.911e+01 -4.390 4.05e-05 ***
sqrt(L1dcache) 5.637e+02 1.297e+02 4.346 4.74e-05 ***
L2cache -8.567e-03 1.252e-03 -6.844 2.71e-09
sqrt(L2cache). 1.040e+00 1.619e-01 6.422 1.54e-08 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.572 on 68 degrees of freedom
(176 observations deleted due to missingness)
Multiple R-squared: 0.9653, Adjusted R-squared: 0.9597
F-statistic: 172 on 11 and 68 DF, p-value: < 2.2e-16
Quitar DieSize:
> int00.lm <- update(int00.lm, .~. - dieSize, data=int00.dat) > summary(int00.lm) Call: lm(formula = nperf ~ clock + cores + voltage + channel + L1icache + sqrt(L1icache) + L1dcache + sqrt(L1dcache) + L2cache + sqrt(L2cache), data = int00.dat) Residuals:
Min 1Q Median 3Q Max -10.0240 -3.5195 0.3577 2.5486 12.0545 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -5.822e+01 3.840e+01 -1.516 0.133913 clock 2.482e-02 1.246e-03 19.922 < 2e-16 *** cores 2.397e+00 1.004e+00 2.389 0.019561 * voltage -2.358e+01 5.495e+00 -4.291 5.52e-05 *** channel 1.399e+02 3.960e+01 3.533 0.000726 *** L1icache 8.703e+01 1.972e+01 4.412 3.57e-05 ***
sqrt(L1icache) -5.768e+02 1.391e+02 -4.146 9.24e-05 *** L1dcache -8.903e+01 1.888e+01 -4.716 1.17e-05 *** sqrt(L1dcache) 5.980e+02 1.282e+02 4.665 1.41e-05 *** L2cache -8.621e-03 1.273e-03 -6.772 3.07e-09 *** sqrt(L2cache) 1.085e+00 1.645e-01 6.598 6.36e-09 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 4.683 on 71 degrees of freedom (174 observations deleted due to missingness) Multiple R-squared: 0.9641, Adjusted R-squared: 0.959 F-statistic: 190.7 on 10 and 71 DF, p-value: < 2.2e-16
En este punto, los valores p para todos los predictores son menores de 0.02, que es menor que nuestro umbral predeterminado de 0.05. Esto nos dice que detengamos el proceso de eliminación hacia atrás. La intuición y la experiencia nos dicen que diez predictores son un número bastante grande para usar en este tipo de modelos. Sin embargo, todos estos predictores tienen valores p por debajo de nuestro umbral de significancia, por lo que no tenemos ninguna razón para excluir ningún predictor específico. Decidimos incluir los diez predictores en el modelo final:
\(\begin{aligned} \text {nperf}=&\ -58.22+0.02482 c \operatorname{loc} k+2.397 \text {cores} \\ &-23.58 \text {voltage}+139.9 \text { channel }+87.03 \text {L1icache} \\ &-576.8 \sqrt{\text {L1icache}}-89.03 L 1 d c a c h e+598 \sqrt{L 1 d c a c h e} \\ &-0.008621 L 2 c a c h e+1.085 \sqrt{L 2 c a c h e} \end{aligned}\)
Mirando hacia atrás sobre la secuencia de modelos que desarrollamos, observe que el número de grados de libertad en cada modelo posterior aumenta a medida que se excluyen los predictores, como se esperaba. En algunos casos, el número de grados de libertad aumenta en más de uno cuando solo se elimina un solo predictor del modelo. Para entender cómo es posible un aumento de más de uno, observe la secuencia de valores en las líneas etiquetadas el número de observaciones caídas por falta de singness
. Estos valores muestran cuántas filas dejó caer la función update ()
porque faltaba el valor de uno de los predictores en esas filas y tenía el valor NA. Cuando el proceso de eliminación hacia atrás eliminó ese predictor del modelo, al menos algunas de esas filas se convirtieron en las que podemos usar para calcular la siguiente versión del modelo, aumentando así el número de grados de libertad.
También observe que, a medida que los predictores bajan del modelo, los valores de R2 se mantienen muy cerca de 0.965. Sin embargo, el valor ajustado de R2 tiende a aumentar muy ligeramente con cada predictor caído. Este incremento indica que el modelo con menos predictores y más grados de libertad tiende a explicar los datos ligeramente mejor que el modelo anterior, que tenía un predictor más. Sin embargo, estos cambios en los valores de R2 son muy pequeños, por lo que no debemos leer demasiado en ellos. Es posible que estos cambios se deban simplemente a fluctuaciones aleatorias de datos. No obstante, es agradable verlas comportándose como esperamos.
En términos generales, la prueba F compara el modelo actual con un modelo con un predictor menos. Si el modelo actual es mejor que el modelo reducido, el valor p será pequeño. En todos nuestros modelos, vemos que el valor p para la prueba F es bastante pequeño y consistente de un modelo a otro. Como resultado, esta prueba F no nos ayuda particularmente a discriminar entre modelos potenciales.