lm() es la función en R para ajustar modelos
lineales.
Es el modelo estadístico más básico que existe y más fácil de
interpretar.
Para interpretarlo se usa la medida R-Cuadrada, que significa qué tan
cerca están los datos de la regresión. Va de 0 a 1, donde 1 es que el
modelo explica toda la variabilidad.
Una inmobiliaria cuenta con registros de casas vendidas, con sus características de superficie, ubicación, estacionamiento y distancias a servicios. Se desea generar un modelo predictivo del precio.
# install.packages("corrplot")
library(corrplot) # sirve para dibujar el mapa de correlaciones
# file.choose()
df <- read.csv("/Users/santiagojaramillo/Library/Mobile Documents/com~apple~CloudDocs/Tec/Semestre 7/Inteligencia Artificial con Impacto Empresarial (Gpo 601)/HousePriceData.csv")
summary(df) # mínimos, máximos y promedios de cada columna
## Observation Dist_Taxi Dist_Market Dist_Hospital
## Min. : 1.0 Min. : 146 Min. : 1666 Min. : 3227
## 1st Qu.:237.0 1st Qu.: 6477 1st Qu.: 9367 1st Qu.:11302
## Median :469.0 Median : 8228 Median :11149 Median :13189
## Mean :468.4 Mean : 8235 Mean :11022 Mean :13091
## 3rd Qu.:700.0 3rd Qu.: 9939 3rd Qu.:12675 3rd Qu.:14855
## Max. :932.0 Max. :20662 Max. :20945 Max. :23294
##
## Carpet Builtup Parking City_Category
## Min. : 775 Min. : 932 Length :905 Length :905
## 1st Qu.: 1317 1st Qu.: 1579 N.unique : 4 N.unique : 3
## Median : 1478 Median : 1774 N.blank : 0 N.blank : 0
## Mean : 1511 Mean : 1794 Min.nchar: 4 Min.nchar: 5
## 3rd Qu.: 1654 3rd Qu.: 1985 Max.nchar: 12 Max.nchar: 5
## Max. :24300 Max. :12730
## NAs :7
## Rainfall House_Price
## Min. :-110.0 Min. : 1492000
## 1st Qu.: 600.0 1st Qu.: 4623000
## Median : 780.0 Median : 5860000
## Mean : 786.9 Mean : 6083992
## 3rd Qu.: 970.0 3rd Qu.: 7200000
## Max. :1560.0 Max. :150000000
##
str(df) # qué tipo de dato es cada columna (número o texto)
## 'data.frame': 905 obs. of 10 variables:
## $ Observation : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Dist_Taxi : int 9796 8294 11001 8301 10510 6665 13153 5882 7495 8233 ...
## $ Dist_Market : int 5250 8186 14399 11188 12629 5142 11869 9948 11589 7067 ...
## $ Dist_Hospital: int 10703 12694 16991 12289 13921 9972 17811 13315 13370 11400 ...
## $ Carpet : int 1659 1461 1340 1451 1770 1442 1542 1261 1090 1030 ...
## $ Builtup : int 1961 1752 1609 1748 2111 1733 1858 1507 1321 1235 ...
## $ Parking : chr "Open" "Not Provided" "Not Provided" "Covered" ...
## $ City_Category: chr "CAT B" "CAT B" "CAT A" "CAT B" ...
## $ Rainfall : int 530 210 720 620 450 760 1030 1020 680 1130 ...
## $ House_Price : int 6649000 3982000 5401000 5373000 4662000 4526000 7224000 3772000 4631000 4415000 ...
head(df) # primeras 6 filas
## Observation Dist_Taxi Dist_Market Dist_Hospital Carpet Builtup Parking
## 1 1 9796 5250 10703 1659 1961 Open
## 2 2 8294 8186 12694 1461 1752 Not Provided
## 3 3 11001 14399 16991 1340 1609 Not Provided
## 4 4 8301 11188 12289 1451 1748 Covered
## 5 5 10510 12629 13921 1770 2111 Not Provided
## 6 6 6665 5142 9972 1442 1733 Open
## City_Category Rainfall House_Price
## 1 CAT B 530 6649000
## 2 CAT B 210 3982000
## 3 CAT A 720 5401000
## 4 CAT B 620 5373000
## 5 CAT B 450 4662000
## 6 CAT B 760 4526000
tail(df) # últimas 6 filas
## Observation Dist_Taxi Dist_Market Dist_Hospital Carpet Builtup Parking
## 900 927 10915 17486 15964 1549 1851 Not Provided
## 901 928 12176 8518 15673 1582 1910 Covered
## 902 929 7214 8717 10553 1387 1663 Open
## 903 930 7423 11708 13220 1200 1436 Open
## 904 931 15082 14700 19617 1299 1560 Open
## 905 932 9297 12537 14418 1174 1429 Covered
## City_Category Rainfall House_Price
## 900 CAT C 1220 7062000
## 901 CAT C 1080 6639000
## 902 CAT A 850 8208000
## 903 CAT A 1060 7644000
## 904 CAT B 770 9661000
## 905 CAT C 1110 5434000
Lo que vemos: son 905 casas y 10 columnas.
House_Price es lo que queremos predecir.
Parking y City_Category son texto
(categorías), el resto son números.
# La correlación solo se puede calcular entre números, por eso primero
# separamos las columnas numéricas.
numericas <- df[sapply(df, is.numeric)]
correlacion <- cor(numericas, use = "complete.obs")
corrplot(correlacion)
Cómo leer el mapa: los círculos azules grandes
significan que dos variables suben juntas. Aquí se ve que
Carpet y Builtup (los dos tamaños de la casa)
están muy relacionados entre sí, y ambos con el precio. Las distancias y
la lluvia casi no tienen color, o sea que no parecen influir en el
precio.
colSums(is.na(df)) # cuenta cuántos datos faltan en cada columna
## Observation Dist_Taxi Dist_Market Dist_Hospital Carpet
## 0 0 0 0 7
## Builtup Parking City_Category Rainfall House_Price
## 0 0 0 0 0
df <- na.omit(df) # borra las filas que tienen datos faltantes
Recomendación: aquí faltaban 7 datos en
Carpet. Al borrarlos quedamos con 898 casas de las 905
originales. Como es menos del 1%, no afecta el modelo. Si hubiera
faltado mucha información sí habría que pensar en rellenar los datos en
lugar de borrarlos.
# El punto (.) significa "usa todas las demás columnas para predecir el precio"
regresion <- lm(House_Price ~ ., data = df)
summary(regresion)
##
## Call:
## lm(formula = House_Price ~ ., data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3694478 -799483 -54242 780191 4539531
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.331e+06 3.781e+05 14.097 < 2e-16 ***
## Observation 4.070e+02 1.524e+02 2.670 0.00773 **
## Dist_Taxi 2.777e+01 2.685e+01 1.034 0.30127
## Dist_Market 1.444e+01 2.083e+01 0.693 0.48839
## Dist_Hospital 4.921e+01 3.011e+01 1.634 0.10257
## Carpet 9.894e+03 1.423e+02 69.508 < 2e-16 ***
## Builtup -7.544e+03 2.407e+02 -31.344 < 2e-16 ***
## ParkingNo Parking -6.156e+05 1.388e+05 -4.435 1.04e-05 ***
## ParkingNot Provided -4.975e+05 1.236e+05 -4.027 6.15e-05 ***
## ParkingOpen -2.575e+05 1.127e+05 -2.285 0.02253 *
## City_CategoryCAT B -1.874e+06 9.613e+04 -19.494 < 2e-16 ***
## City_CategoryCAT C -2.897e+06 1.059e+05 -27.367 < 2e-16 ***
## Rainfall -9.559e+01 1.543e+02 -0.620 0.53564
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1224000 on 885 degrees of freedom
## Multiple R-squared: 0.9433, Adjusted R-squared: 0.9426
## F-statistic: 1228 on 12 and 885 DF, p-value: < 2.2e-16
Cómo leer esto: hay que fijarse en las estrellas del lado derecho. Entre más estrellas, más importante es esa variable para explicar el precio.
Carpet,
Builtup, Parking y
City_Category.Dist_Taxi,
Dist_Market, Dist_Hospital y
Rainfall.La R-cuadrada es 0.9433, o sea que este modelo explica el 94% de por qué una casa cuesta lo que cuesta. Está muy bien.
Recomendación: Observation aparece con
estrellas, pero no hay que usarla. Es solo el número de fila (1, 2, 3…),
no una característica real de la casa. Que salga significativa es pura
coincidencia.
# Quitamos las variables que no servían y nos quedamos solo con las importantes
regresion2 <- lm(House_Price ~ Carpet + Builtup + Parking +
City_Category, data = df)
summary(regresion2)
##
## Call:
## lm(formula = House_Price ~ Carpet + Builtup + Parking + City_Category,
## data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3430967 -802513 -46915 775070 4263090
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6477702.2 272077.2 23.808 < 2e-16 ***
## Carpet 9968.8 143.3 69.584 < 2e-16 ***
## Builtup -7611.6 243.3 -31.279 < 2e-16 ***
## ParkingNo Parking -536301.8 139943.6 -3.832 0.000136 ***
## ParkingNot Provided -457380.4 125020.1 -3.658 0.000269 ***
## ParkingOpen -236576.3 114356.8 -2.069 0.038857 *
## City_CategoryCAT B -1918518.1 97007.4 -19.777 < 2e-16 ***
## City_CategoryCAT C -2908756.6 107359.6 -27.094 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1243000 on 890 degrees of freedom
## Multiple R-squared: 0.9412, Adjusted R-squared: 0.9407
## F-statistic: 2034 on 7 and 890 DF, p-value: < 2.2e-16
Resultado: la R-cuadrada bajó apenas de 0.9433 a 0.9412, casi nada. Esto quiere decir que las 4 variables que quitamos de verdad no aportaban.
Recomendación: siempre conviene quedarse con el modelo más simple cuando explica prácticamente lo mismo. Es más fácil de entender y de usar.
Qué significan los números:
Carpet: cada metro extra de superficie sube el precio
unos $9,969.Builtup: sale en negativo porque ya está contada la
superficie en Carpet; las dos miden casi lo mismo y el
modelo las compensa entre sí.City_Category: aquí está la diferencia más grande.
Comparada con CAT A, una casa igual en CAT B cuesta $1.9
millones menos y en CAT C $2.9 millones
menos.Parking: no tener estacionamiento baja el precio unos
$536,000 contra tenerlo cubierto.# Inventamos una casa y le pedimos al modelo que calcule su precio.
# Dejamos todo igual y solo cambiamos la ciudad, para comparar.
datos_nuevos <- data.frame(
Carpet = 1500,
Builtup = 1800,
Parking = "Covered",
City_Category = c("CAT A", "CAT B", "CAT C")
)
predict(regresion2, newdata = datos_nuevos)
## 1 2 3
## 7729938 5811420 4821181
Interpretación: la misma casa (1500 de superficie, 1800 de construcción y estacionamiento cubierto) valdría $7.7 millones en CAT A, $5.8 millones en CAT B y $4.8 millones en CAT C.
Conclusión y recomendación: para esta inmobiliaria, lo que más define el precio es la zona de la ciudad y el tamaño de la casa. Qué tan cerca esté del taxi, del mercado o del hospital no cambia el precio, así que no vale la pena usarlo como argumento de venta.