El Trabajo de Fin de Master lo he basado en el estudio, adaptación y generacion de modelo, usando el dataset que se provee en Kaggle con precios de viviendas en Iowa. Lo que más me ha atraido de este dataset, es la posiblidad de aprender sobre la parte de preparación de los datos. Ya que si bien no es un dataset muy grande (1460 observables), disponemos de 81 variables de todo tipo. Tenemos variables continuas, discretas, ordinales, nominales.
Esta variedad, sin ser un dataset extenso como digo, me ha permitido el poder estudiar detalladamente el dataset, para tomar decisioens sobre como transformarlo (creación de variables dummie), como eliminar valores atípicos (outliers), eliminar valores nulos (missing values). Además he podido tomar decisiones sobre como transformar algunas varibles para poder usarlas de forma más sencilla.
Esta cantidad y variedad de variables también ha hecho que sea algo complejo y sobre todo entretenido este trabajo de tratamiento. Pero he considerado importante el centrarme en ello ya que es una tarea muy importante y que debido al tiempo que hemos tenido, quizás se ha pasado un poco más por alto. He tratado de usar ténicas para simplicar la tarea y gracias a que R provee de muchas librerias especificas alguna de ellas se me han simplicado.
Se incluyen en los anexos documentación sobre los nombres de las variables y su significado por si se requiere, pero la mayoría han sido comentadas durante el estudio.
El finl último de todo este estudio es la creación de un modelo. El modelo utilizado ha sido una regresión lineal multivariable, que si bien no es muy glamuroso ha dado buen resultado. Se ha utilizando este modelo de regresión ya que la variable es continua.
Vamos a realizar la carga del dataset, este dataset lo he descargado de Git. En Kaggle se proporcionan dos datasets, uno de entrenamiento y otro de test. El dataset de test no provee de la variable objetivo, que es SalePrice, ya que está destinado a usarlo para remitir el resultado y que sea evaluado nuestro trabajo. Usaremos el dataset de entrenamiento, pero prepararemos el código para poder adaptar el dataset de test.
library(readr)
#Nombramos el dataset como entrenamiento aunque Después lo dividiremos para hacer el training y el test
dat_train <- read_csv("./data/train.csv")
#Este es el dataset de test que provee kaggle pero no dispone de la variable SalePrice, para ser devuelto con la predicción por lo que para este modelo no nos servirá.
#dat_test <- read_csv("./data/test.csv")
Veamos el número de filas y columnas que tiene nuestro dataset:
dim(dat_train)
## [1] 1460 81
Vemos que tenemos 1460 observables y 81 variables. Entre estas variables tenemos de todo tipo, continuas, discretas, categoricas…
Ejecutamos un summary para revisar los datos que hemos cargado:
summary(dat_train)
## Id MSSubClass MSZoning LotFrontage
## Min. : 1.0 Min. : 20.0 Length:1460 Min. : 21.00
## 1st Qu.: 365.8 1st Qu.: 20.0 Class :character 1st Qu.: 59.00
## Median : 730.5 Median : 50.0 Mode :character Median : 69.00
## Mean : 730.5 Mean : 56.9 Mean : 70.05
## 3rd Qu.:1095.2 3rd Qu.: 70.0 3rd Qu.: 80.00
## Max. :1460.0 Max. :190.0 Max. :313.00
## NA's :259
## LotArea Street Alley LotShape
## Min. : 1300 Length:1460 Length:1460 Length:1460
## 1st Qu.: 7554 Class :character Class :character Class :character
## Median : 9478 Mode :character Mode :character Mode :character
## Mean : 10517
## 3rd Qu.: 11602
## Max. :215245
##
## LandContour Utilities LotConfig
## Length:1460 Length:1460 Length:1460
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
##
## LandSlope Neighborhood Condition1
## Length:1460 Length:1460 Length:1460
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
##
## Condition2 BldgType HouseStyle OverallQual
## Length:1460 Length:1460 Length:1460 Min. : 1.000
## Class :character Class :character Class :character 1st Qu.: 5.000
## Mode :character Mode :character Mode :character Median : 6.000
## Mean : 6.099
## 3rd Qu.: 7.000
## Max. :10.000
##
## OverallCond YearBuilt YearRemodAdd RoofStyle
## Min. :1.000 Min. :1872 Min. :1950 Length:1460
## 1st Qu.:5.000 1st Qu.:1954 1st Qu.:1967 Class :character
## Median :5.000 Median :1973 Median :1994 Mode :character
## Mean :5.575 Mean :1971 Mean :1985
## 3rd Qu.:6.000 3rd Qu.:2000 3rd Qu.:2004
## Max. :9.000 Max. :2010 Max. :2010
##
## RoofMatl Exterior1st Exterior2nd
## Length:1460 Length:1460 Length:1460
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
##
## MasVnrType MasVnrArea ExterQual ExterCond
## Length:1460 Min. : 0.0 Length:1460 Length:1460
## Class :character 1st Qu.: 0.0 Class :character Class :character
## Mode :character Median : 0.0 Mode :character Mode :character
## Mean : 103.7
## 3rd Qu.: 166.0
## Max. :1600.0
## NA's :8
## Foundation BsmtQual BsmtCond
## Length:1460 Length:1460 Length:1460
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
##
## BsmtExposure BsmtFinType1 BsmtFinSF1 BsmtFinType2
## Length:1460 Length:1460 Min. : 0.0 Length:1460
## Class :character Class :character 1st Qu.: 0.0 Class :character
## Mode :character Mode :character Median : 383.5 Mode :character
## Mean : 443.6
## 3rd Qu.: 712.2
## Max. :5644.0
##
## BsmtFinSF2 BsmtUnfSF TotalBsmtSF Heating
## Min. : 0.00 Min. : 0.0 Min. : 0.0 Length:1460
## 1st Qu.: 0.00 1st Qu.: 223.0 1st Qu.: 795.8 Class :character
## Median : 0.00 Median : 477.5 Median : 991.5 Mode :character
## Mean : 46.55 Mean : 567.2 Mean :1057.4
## 3rd Qu.: 0.00 3rd Qu.: 808.0 3rd Qu.:1298.2
## Max. :1474.00 Max. :2336.0 Max. :6110.0
##
## HeatingQC CentralAir Electrical 1stFlrSF
## Length:1460 Length:1460 Length:1460 Min. : 334
## Class :character Class :character Class :character 1st Qu.: 882
## Mode :character Mode :character Mode :character Median :1087
## Mean :1163
## 3rd Qu.:1391
## Max. :4692
##
## 2ndFlrSF LowQualFinSF GrLivArea BsmtFullBath
## Min. : 0 Min. : 0.000 Min. : 334 Min. :0.0000
## 1st Qu.: 0 1st Qu.: 0.000 1st Qu.:1130 1st Qu.:0.0000
## Median : 0 Median : 0.000 Median :1464 Median :0.0000
## Mean : 347 Mean : 5.845 Mean :1515 Mean :0.4253
## 3rd Qu.: 728 3rd Qu.: 0.000 3rd Qu.:1777 3rd Qu.:1.0000
## Max. :2065 Max. :572.000 Max. :5642 Max. :3.0000
##
## BsmtHalfBath FullBath HalfBath BedroomAbvGr
## Min. :0.00000 Min. :0.000 Min. :0.0000 Min. :0.000
## 1st Qu.:0.00000 1st Qu.:1.000 1st Qu.:0.0000 1st Qu.:2.000
## Median :0.00000 Median :2.000 Median :0.0000 Median :3.000
## Mean :0.05753 Mean :1.565 Mean :0.3829 Mean :2.866
## 3rd Qu.:0.00000 3rd Qu.:2.000 3rd Qu.:1.0000 3rd Qu.:3.000
## Max. :2.00000 Max. :3.000 Max. :2.0000 Max. :8.000
##
## KitchenAbvGr KitchenQual TotRmsAbvGrd Functional
## Min. :0.000 Length:1460 Min. : 2.000 Length:1460
## 1st Qu.:1.000 Class :character 1st Qu.: 5.000 Class :character
## Median :1.000 Mode :character Median : 6.000 Mode :character
## Mean :1.047 Mean : 6.518
## 3rd Qu.:1.000 3rd Qu.: 7.000
## Max. :3.000 Max. :14.000
##
## Fireplaces FireplaceQu GarageType GarageYrBlt
## Min. :0.000 Length:1460 Length:1460 Min. :1900
## 1st Qu.:0.000 Class :character Class :character 1st Qu.:1961
## Median :1.000 Mode :character Mode :character Median :1980
## Mean :0.613 Mean :1979
## 3rd Qu.:1.000 3rd Qu.:2002
## Max. :3.000 Max. :2010
## NA's :81
## GarageFinish GarageCars GarageArea GarageQual
## Length:1460 Min. :0.000 Min. : 0.0 Length:1460
## Class :character 1st Qu.:1.000 1st Qu.: 334.5 Class :character
## Mode :character Median :2.000 Median : 480.0 Mode :character
## Mean :1.767 Mean : 473.0
## 3rd Qu.:2.000 3rd Qu.: 576.0
## Max. :4.000 Max. :1418.0
##
## GarageCond PavedDrive WoodDeckSF OpenPorchSF
## Length:1460 Length:1460 Min. : 0.00 Min. : 0.00
## Class :character Class :character 1st Qu.: 0.00 1st Qu.: 0.00
## Mode :character Mode :character Median : 0.00 Median : 25.00
## Mean : 94.24 Mean : 46.66
## 3rd Qu.:168.00 3rd Qu.: 68.00
## Max. :857.00 Max. :547.00
##
## EnclosedPorch 3SsnPorch ScreenPorch PoolArea
## Min. : 0.00 Min. : 0.00 Min. : 0.00 Min. : 0.000
## 1st Qu.: 0.00 1st Qu.: 0.00 1st Qu.: 0.00 1st Qu.: 0.000
## Median : 0.00 Median : 0.00 Median : 0.00 Median : 0.000
## Mean : 21.95 Mean : 3.41 Mean : 15.06 Mean : 2.759
## 3rd Qu.: 0.00 3rd Qu.: 0.00 3rd Qu.: 0.00 3rd Qu.: 0.000
## Max. :552.00 Max. :508.00 Max. :480.00 Max. :738.000
##
## PoolQC Fence MiscFeature
## Length:1460 Length:1460 Length:1460
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
##
## MiscVal MoSold YrSold SaleType
## Min. : 0.00 Min. : 1.000 Min. :2006 Length:1460
## 1st Qu.: 0.00 1st Qu.: 5.000 1st Qu.:2007 Class :character
## Median : 0.00 Median : 6.000 Median :2008 Mode :character
## Mean : 43.49 Mean : 6.322 Mean :2008
## 3rd Qu.: 0.00 3rd Qu.: 8.000 3rd Qu.:2009
## Max. :15500.00 Max. :12.000 Max. :2010
##
## SaleCondition SalePrice
## Length:1460 Min. : 34900
## Class :character 1st Qu.:129975
## Mode :character Median :163000
## Mean :180921
## 3rd Qu.:214000
## Max. :755000
##
En este dataset he considerado 46 variables categoricas (entre nominales y ordinales), 21 variables continuas y 14 discretas. La variable id se eliminará ya que no es representativa. Como variable objetivo, como es lógico será la variable precio de la vivienda (SalePrice) que es continua.
Vamos a estudiar las variables categoricas que tenemos, vamos a realizar una visualización de sus datos y para ello definimos primero las funciones que nos permitirán dibujar los histogramas:
plotHist <- function(data_in,name){
p <- ggplot(data=data_in, aes(factor(data_in[[1]]))) + stat_count() + xlab(name) + theme_light() +
theme(axis.text.x = element_text(angle = 70, hjust =1))
return(p)
}
#creamos una función para poder dibujar los histogramas.
doHists <- function(data_in,names_to_plot, num_cols){
plots <- list()
for (i in 1:length(names_to_plot)) {
data_plot <- data.frame(data_in[names_to_plot[i]])
plt <- plotHist(data_plot,names_to_plot[[i]])
plots <- c(plots, list(plt))
}
do.call("grid.arrange", c(plots, ncol=num_cols))
}
Vamos a dibujar las gráficas para las variables categoricas indicadas en el vector:
nom_col <- c("MSSubClass","MSZoning","Street","Alley","LotShape","LandContour","Utilities","LotConfig","LandSlope")
doHists(dat_train,nom_col,3)
Revisando las gráficas podemos ver (las descripciones de los campos y sus valores se encuentran en los anexos):
Aquí se representan como ordinales variables que son de tipo numérico, ya que son la representación númerica de un clasificación u ordenación, podrían haber sido representadas por su valores en caracter y requerir su transformación, pero ya se han indicado como numéricas, por ello las incluyo dentro de las variables categóricas.
nom_col <- c("Neighborhood","Condition1")
doHists(dat_train,nom_col,2)
En este caso sólo hemos dibujado dos para que se pudierá ver claramente la variable vecindario:
nom_col <- c("Condition2","BldgType","HouseStyle","OverallQual", "OverallCond","RoofStyle","RoofMatl","Exterior1st","Exterior2nd")
doHists(dat_train,nom_col,3)
La variables aquí representadas son:
nom_col <- c("MasVnrType","ExterQual","ExterCond","Foundation","BsmtQual","BsmtCond","BsmtExposure","BsmtFinType1","BsmtFinType2")
doHists(dat_train,nom_col,3)
La variables aquí representadas son:
nom_col <- c("Heating","HeatingQC","CentralAir","Electrical","KitchenQual", "Functional","FireplaceQu", "GarageType", "GarageFinish")
doHists(dat_train,nom_col,3)
En las variables aquí representadas tenemos:
nom_col <- c("GarageQual", "GarageCond","PavedDrive", "PoolQC","Fence","MiscFeature","SaleType","SaleCondition")
doHists(dat_train,nom_col,3)
En la representación de estas variables vemos:
De este estudio podremos inferir las transformaciones que se realizarán más adelante.
Vamos a proceder de forma parecida con la varibles continuas, vamos a generar gráficas de densidad y podremos analizar los datos de los que disponemos.
#creamos una función donde parametrizamos que queremos dibujar
plotDesn <- function(data_in,name){
p <- ggplot(data=data_in) + geom_line(aes(x = data_in[[1]]), stat = 'density', size = 1,alpha = 1.0) +
xlab(name) + theme_light()
return(p)
}
#creamos una función para poder dibujar las gráficas de densidad en un grid.
doDens <- function(data_in,names_to_plot, num_cols){
plots <- list()
for (i in 1:length(names_to_plot)) {
data_plot <- data.frame(data_in[names_to_plot[i]])
plt <- plotDesn(data_in=data_plot,name=names_to_plot[[i]])
plots <- c(plots, list(plt))
}
do.call("grid.arrange", c(plots, ncol=num_cols))
}
Vamos a visualizar primero la variable objetivo SalePrice, frente a la superficie de la vivienda:
nom_col <- c("SalePrice","GrLivArea")
doDens(dat_train,nom_col,1)
Se aprecia asimetría positiva en la muestra, un sesgo claro hacia la izquierda. Se puede ver además que hay algún observable para el cual la varible precio está muy por encima de media, lo que da por pensar en un outlier. Esto lo revisaremos más tarde en un apartado especifico.
Dibujamos a continuación las variables que tienen que ver con las superficie de la casa, tanto de la zona habitable como del sotano y parcela:
nom_col <- c("GrLivArea","TotalBsmtSF","LotArea")
doDens(dat_train,nom_col,1)
Como podemos ver junto con el precio, las tres tienen una asimetria positiva, un claro sesgo de nuestro dataset, que es lógico teniendo en cuenta que no debe haber muchas casas con tanta superficie como se ve que hay alguna. Esto como he indicado antes nos muestra los posibles outliners que podemos tener en nuestro dataset. Para hacernos una idea de lo que es un pie cuadrado es 0.09 metros cuadrados, dividiendo entre 10 tendríamos una aproximación a los metros cuadrados. Vemos que la mayor parte de la viviendas estarían entre los 100 y 175 metros cuadrados de zona habitable, y de sotano entre 80 y 120. La parcela es algo más dificl de calcular debido a los outliers.
Procedemos a dibujar el resto de variables continuas que entiendo no deberían tener tanto peso:
nom_col <- c("LotFrontage","MasVnrArea","BsmtFinSF1","BsmtFinSF2","BsmtUnfSF","1stFlrSF")
doDens(dat_train,nom_col,2)
## Warning: Removed 259 rows containing non-finite values (stat_density).
## Warning: Removed 8 rows containing non-finite values (stat_density).
Revisando las gráficas vemos:
nom_col <- c("2ndFlrSF","LowQualFinSF","GarageArea","WoodDeckSF","OpenPorchSF","EnclosedPorch")
doDens(dat_train,nom_col,2)
En la gráfica se visualizan las siguientes variables:
nom_col <- c("3SsnPorch","ScreenPorch","PoolArea","MiscVal")
doDens(dat_train,nom_col,2)
Describimos las variables de las gráficas:
Para dibujar las variables discretas vamos a utilizar el histograma, ya que la mayoría no tiene una gran variadad de datos:
nom_col <- c("YearBuilt")
doHists(dat_train,nom_col,1)
En este caso, para el año de construcción en la gráfica no se ven los años de forma correcta, aunque se intuye que el mayor número de casas vendidas corresponde con los años de mayor crecimiento inmobiliario, que se produjo en todos los paises desarrollados. Se ve además los úlitmos años de la crisis muy bien reflejados, con ventas muy bajas sobre todo en el 2010.
nom_col <- c("YearRemodAdd")
doHists(dat_train,nom_col,1)
El caso del año de remodelación, hay que tener en cuenta que si la casa no se ha remodelado, tendrá el mismo año que la fecha de construcción. por lo que aquí habrá casas que no hayan pasado por esa remodelación, entre ellas pueden estarlas de la epoca de crecimiento inmobiliario, ya que son las casas más nuevas.
nom_col <- c("BsmtFullBath","BsmtHalfBath","FullBath","HalfBath","BedroomAbvGr","KitchenAbvGr")
doHists(dat_train,nom_col,2)
Las variables aquí representadas son:
nom_col <- c("TotRmsAbvGrd","Fireplaces","GarageCars","MoSold","YrSold")
doHists(dat_train,nom_col,2)
Las anteriores gráficas corresponden con las variables:
nom_col <- c("GarageYrBlt")
doHists(dat_train,nom_col,1)
Como en el caso del año de construcción es dificil ver los años pero el comportamento, como es lógico es similar. Hay una diferencia significativa y es que hay varios valores a N/A que siginifica que la casas no tendrá garaje, como veremos más adelante 81.
Vamos a tratar de detectar que valores hay nulos dentro de nuestro dataset que puedan influir en el modelo. Dependiendo del dato se podrá inferir un valor o eliminarlo, si se ve que es un dato que no aportará valor al modelo. Para detectar lo valores nulos vamos a ejecutar el siguiente script:
colSums(sapply(dat_train, is.na))
## Id MSSubClass MSZoning LotFrontage LotArea
## 0 0 0 259 0
## Street Alley LotShape LandContour Utilities
## 0 1369 0 0 0
## LotConfig LandSlope Neighborhood Condition1 Condition2
## 0 0 0 0 0
## BldgType HouseStyle OverallQual OverallCond YearBuilt
## 0 0 0 0 0
## YearRemodAdd RoofStyle RoofMatl Exterior1st Exterior2nd
## 0 0 0 0 0
## MasVnrType MasVnrArea ExterQual ExterCond Foundation
## 8 8 0 0 0
## BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinSF1
## 37 37 38 37 0
## BsmtFinType2 BsmtFinSF2 BsmtUnfSF TotalBsmtSF Heating
## 38 0 0 0 0
## HeatingQC CentralAir Electrical 1stFlrSF 2ndFlrSF
## 0 0 1 0 0
## LowQualFinSF GrLivArea BsmtFullBath BsmtHalfBath FullBath
## 0 0 0 0 0
## HalfBath BedroomAbvGr KitchenAbvGr KitchenQual TotRmsAbvGrd
## 0 0 0 0 0
## Functional Fireplaces FireplaceQu GarageType GarageYrBlt
## 0 0 690 81 81
## GarageFinish GarageCars GarageArea GarageQual GarageCond
## 81 0 0 81 81
## PavedDrive WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch
## 0 0 0 0 0
## ScreenPorch PoolArea PoolQC Fence MiscFeature
## 0 0 1453 1179 1406
## MiscVal MoSold YrSold SaleType SaleCondition
## 0 0 0 0 0
## SalePrice
## 0
Vamos a analizar variable a variable:
Para los siguientes casos, que corresponden con caracteristicas del sotano, vemos que hay variables con 37 y otras con 38 nulos. Vamos a revisar primero si en el dataset nos podemos encontrar que tenemos área del sotano, pero no se han evaluado estos casos o son casos para los cuales no hay sotano:
dat_train %>% filter(TotalBsmtSF==0) %>% count()
## # A tibble: 1 x 1
## n
## <int>
## 1 37
Vemos en este caso que tenemos 37 filas para las cuales no hay una evaluación de las variables nulas, pero hay que revisar el caso para el cual no tenemos evaluación para las variables BsmtExposure y BsmtFinType2.
dat_train %>% filter(is.na(BsmtExposure)) %>%filter(TotalBsmtSF!=0) %>% select(Id, TotalBsmtSF, BsmtQual, BsmtExposure, BsmtFinSF1 ,BsmtFinType1, BsmtFinType2,BsmtFinSF2)
## # A tibble: 1 x 8
## Id TotalBsmtSF BsmtQual BsmtExposure BsmtFinSF1 BsmtFinType1
## <int> <int> <chr> <chr> <int> <chr>
## 1 949 936 Gd <NA> 0 Unf
## # ... with 2 more variables: BsmtFinType2 <chr>, BsmtFinSF2 <int>
dat_train %>% filter(is.na(BsmtFinType2)) %>%filter(TotalBsmtSF!=0) %>% select(Id, TotalBsmtSF, BsmtQual, BsmtExposure, BsmtFinSF1 ,BsmtFinType1, BsmtFinType2,BsmtFinSF2)
## # A tibble: 1 x 8
## Id TotalBsmtSF BsmtQual BsmtExposure BsmtFinSF1 BsmtFinType1
## <int> <int> <chr> <chr> <int> <chr>
## 1 333 3206 Gd No 1124 GLQ
## # ... with 2 more variables: BsmtFinType2 <chr>, BsmtFinSF2 <int>
Vamos a revisar el caso para cada variable:
dat_train %>% filter(between(TotalBsmtSF, 900,1000)) %>% filter (BsmtQual=='Gd', BsmtFinSF1==0,BsmtFinType1=='Unf', BsmtFinType2=='Unf',BsmtFinSF2==0) %>% group_by(BsmtExposure) %>% count()
## # A tibble: 3 x 2
## # Groups: BsmtExposure [3]
## BsmtExposure n
## <chr> <int>
## 1 Av 2
## 2 No 19
## 3 <NA> 1
Podemos ver que para casos similares la mayoría tiene el valor No (No exposure), por lo que para este caso lo modificamos a ese valor:
dat_train$BsmtExposure[dat_train$Id == 949] <- "No"
dat_train %>% filter(between(TotalBsmtSF, 2000,4000)) %>% filter (BsmtQual=='Gd', BsmtFinType1=='GLQ', BsmtFinType2=='Unf') %>% group_by(BsmtFinType2) %>% count()
## # A tibble: 1 x 2
## # Groups: BsmtFinType2 [1]
## BsmtFinType2 n
## <chr> <int>
## 1 Unf 4
Debido a las caracteristicas de este parámetro no hay mucha duda lo modificamos a este valor:
dat_train$BsmtFinType2[dat_train$Id == 333] <- "Unf"
Seguimos con el resto de variables:
dat_train %>% filter(is.na(Electrical)) %>% select(Heating,CentralAir)
## # A tibble: 1 x 2
## Heating CentralAir
## <chr> <chr>
## 1 GasA Y
Parece que no es el caso ya que aire acondicionado si tienen. Por lo que pondremos el valor ‘SBrkr’ que es el estandar.
dat_train %>% filter(Fireplaces==0, is.na(FireplaceQu)) %>% count()
## # A tibble: 1 x 1
## n
## <int>
## 1 690
Parece que no es el caso. Por lo que todos los valores NA corresponden a casas sin chimenea. Para todos estos casos inferiremos un 0 ya que modificaremos los valores para que sean ordinales numéricos. de 0 hasta 5, indicando la calidad de mayor a menor.
Dentro del grupo de variables nulas sobre garage vamos a revisar si corresponde con casas que no disponen de garage.
dat_train %>% filter(GarageArea!=0,is.na(GarageType), is.na(GarageYrBlt), is.na(GarageFinish)) %>% count()
## # A tibble: 1 x 1
## n
## <int>
## 1 0
Como podemos ver, es así, por lo que vamos a revisar las variables para estudiar la manera de proceder:
Las tres variables siguientes debido a los pocos observables que las tienen informadas las eliminaremos del dataset: PoolQC, Fence,MiscFeature.
Vamos a pasar a revisar los posibles valores atípicos que podemos tener, vamos a centrarnos en el precio de la vivienda y los metros cuadrados. Para ello vamos a dibujar dos gráficas para comprar el precio de la vivivienda con la localización y el precio de la vivienda con los metros cuadrados. Estudiando estos dos valores seguramente eliminemos la mayoría de los outliners de cualquier otro tipo de variable.
Vamos a dibujar un boxplot donde representaremos el precio frente a la zona de venta del la casa:
ggplot(dat_train, aes(x=Neighborhood, y=SalePrice)) + xlab("Precio vs Vecindario") + geom_boxplot(outlier.colour="red", outlier.shape=1,outlier.size=2) + theme_light() + theme(axis.text.x = element_text(angle = 70, hjust =1))
Como podemos ver dependiendo de barrio hay varios outliners, en los barrios de Northridge (NoRidge) y el de Northridge Heigths (NridgHt). Vamos a representar ahora una gráfica de precio frente a la superficie de la vivienda:
qplot(GrLivArea, SalePrice, data = dat_train, colour=Neighborhood)+ xlab("Precio vs Superficie Total")+theme_light()
En esta gráfica se puede ver claramente que para las casas de más de 3500 pies cuadrados de superficie tenemos o precios muy altos o muy bajos en proporción al tamaño de la vivienda. Ademas se puede ver que tenemos por encima de los 500.000, varias casas que parecen que su precio está muy por encima de lo que les correponde por superficie. Si nos fijamos por el vecindario, se constata que estos datos a eliminar son outliners, ya que o bien en metros o bien en precio, se separan mucho de la agrupación del vecindario.
Con lo que hemos visto en los apartados anteriores, vamos a modificar nuestro dataset, vamos a dividirlo en distintos apartados y creando funciones para encapsular, de esta forma me permite ejecutando un único chunk volver a modificar todo el dataset. Además que cuando quiera usar el dataset de test de kaggle podré reutilizarlo facilmente.
Vamos a aplicar las modificaciones que ya habíamos visto en el apartado especifico. Lo encapsulo en una función, de esta manera cuando quiera usar el dataset de test provisto por kaggle (que no dispone de la variable SalePrice) lo podré modificar facilmente:
missingValues <- function (datos){
r_dat <- datos
#Eliminamos del daset las varaibles : Alley,PoolQC, MiscFeature y Fence.
r_dat<- r_dat[,!colnames(r_dat)=="Alley"]
r_dat<- r_dat[,!colnames(r_dat)=="PoolQC"]
r_dat<- r_dat[,!colnames(r_dat)=="MiscFeature"]
r_dat<- r_dat[,!colnames(r_dat)=="Fence"]
#Modificamos los valores nulos de las siguientes varibles
r_dat$LotFrontage[is.na(r_dat$LotFrontage)] <- 0
r_dat$MasVnrArea[is.na(r_dat$MasVnrArea)] <- 0
r_dat$GarageFinish[is.na(r_dat$GarageFinish)] <- '0'
r_dat$MasVnrType[is.na(r_dat$MasVnrType)] <- 'None'
r_dat$Electrical[is.na(r_dat$Electrical)] <- 'SBrkr'
#Estas variables son ordinales e inferimos un 0 para los valores nulos.
r_dat$BsmtCond[is.na(r_dat$BsmtCond)] <- '0'
r_dat$BsmtExposure[is.na(r_dat$BsmtExposure)] <- '0'
r_dat$FireplaceQu[is.na(r_dat$FireplaceQu)] <- '0'
r_dat$BsmtQual[is.na(r_dat$BsmtQual)] <- '0'
r_dat$GarageQual[is.na(r_dat$GarageQual)] <- '0'
r_dat$GarageCond[is.na(r_dat$GarageCond)] <- '0'
#Esta variable la vamos a asimilar a un ordinal por lo que inferimos o para el caso de no tener Garaje
r_dat$GarageFinish[is.na(r_dat$GarageFinish)] <- '0'
r_dat$BsmtFinType1[is.na(r_dat$BsmtFinType1)] <- '0'
r_dat$BsmtFinType2[is.na(r_dat$BsmtFinType2)] <- '0'
#Estas variables las voy a convertir a variables dummy pero quiero eliminar todos los valores nulos en esta función, por ello lo modifico al valor 0, pero no sería necesario a tener este tipo de variables.
r_dat$GarageType[is.na(r_dat$GarageType)] <- 'None'
#Para los años que tenemos nulos le pondemos cero.
r_dat$GarageYrBlt[is.na(r_dat$GarageYrBlt)] <- 0
return(r_dat)
}
Ha dado valor a todas las variables incluido GarageType, después, cuando hagamos el tratamiento para las variables dummy, eliminaré esta columna.
Como habíamos valorado antes vamos a eliminar todos los observables con precio por encima de 500000 y los que su superficie sea superior a 3500 pies cuadrados. Incluimos un booleano test para cuando ejecutemos con el dataset de test de kaggle ya que no dispone de la variable SalePrice.
delOutliers <- function(datos,test){
r_dat <- datos
if(!test){
r_dat<-r_dat %>% filter(!SalePrice>500000)
}
r_dat<-r_dat %>% filter(!GrLivArea>3500)
return(r_dat)
}
Para las variables ordinales vamos a realizar una transformación sencilla, vamos a convertirlo en numérico dando al de mayor valor un 5 y al de menor valor o bien un 1 o un 0 en caso que hay sido valor nulo. Vamos a convertir tambien las variables ordinales BsmtFinType1, BsmtFinType2, GarageFinish que expresa la calidad del acabado del garaje.
ordinals <- function(datos){
r_dat <- datos
#Modificamos las variables de calidad
qual_list <- c('0' = 0 ,'Po' = 1, 'Fa' = 2, 'TA' = 3, 'Gd' = 4, 'Ex' = 5)
r_dat$ExterQual <- as.numeric(qual_list[r_dat$ExterQual])
r_dat$ExterCond <- as.numeric(qual_list[r_dat$ExterCond])
r_dat$BsmtQual <- as.numeric(qual_list[r_dat$BsmtQual])
r_dat$BsmtCond <- as.numeric(qual_list[r_dat$BsmtCond])
r_dat$HeatingQC <- as.numeric(qual_list[r_dat$HeatingQC])
r_dat$KitchenQual <- as.numeric(qual_list[r_dat$KitchenQual])
r_dat$FireplaceQu <- as.numeric(qual_list[r_dat$FireplaceQu])
r_dat$GarageQual <- as.numeric(qual_list[r_dat$GarageQual])
r_dat$GarageCond <- as.numeric(qual_list[r_dat$GarageCond])
#vamos a modificar BsmtExposure
expo_list <- c('Gd' = 4, 'Av' = 3, 'Mn' = 2, 'No' = 1, '0' = 0)
r_dat$BsmtExposure <- as.numeric(expo_list[r_dat$BsmtExposure])
# Vamos con las variables BsmtFinType1 y 2
bsmtFintp_list <- c('GLQ' = 6, 'ALQ' = 5, 'BLQ' = 4 , 'Rec' = 3, 'LwQ' = 2, 'Unf' = 1, '0' = 0 )
r_dat$BsmtFinType1 <- as.numeric(bsmtFintp_list[r_dat$BsmtFinType1])
r_dat$BsmtFinType2 <- as.numeric(bsmtFintp_list[r_dat$BsmtFinType2])
#Actuamos de forma similar para las variables de garage
grg_list <- c('Fin' = 5, 'RFn' = 4, 'Unf' = 3, '0' = 0 )
r_dat$GarageFinish <- as.numeric(grg_list[r_dat$GarageFinish])
return(r_dat)
}
Algunas de las variables que tenemos la vamos a convertir a variables dicotómicas ya que de los valores disponibles, sólo es representativo uno de ellos, al cual le daremos el valor 1 y al resto el valor cero.
simplyTransforms <- function(datos){
r_dat <- datos
#Consideramos que la mayoría tienen una superfie regular y el resto no.
r_dat$MSZoning[r_dat$MSZoning != "RL"] <- 0
r_dat$MSZoning[r_dat$MSZoning == "RL"] <- 1
r_dat$MSZoning<-as.numeric(r_dat$MSZoning)
#La mayoría de las casas tienen la calle pavimentada
r_dat$Street[r_dat$Street != "Pave"] <- 0
r_dat$Street[r_dat$Street == "Pave"] <- 1
r_dat$Street<-as.numeric(r_dat$Street)
#La forma de los lotes es regular para la mayoría, y el resto irregular
r_dat$LotShape[r_dat$LotShape != "Reg"] <- 0
r_dat$LotShape[r_dat$LotShape == "Reg"] <- 1
r_dat$LotShape<-as.numeric(r_dat$LotShape)
#La mayoría de las propiedasdes están sobre superficie plana
r_dat$LandContour[r_dat$LandContour != "Lvl"] <- 0
r_dat$LandContour[r_dat$LandContour == "Lvl"] <- 1
r_dat$LandContour<-as.numeric(r_dat$LandContour)
#Tomamos como 0 las propiedades que no tienen todos los servicios públicos
r_dat$Utilities[r_dat$Utilities != "AllPub"] <- 0
r_dat$Utilities[r_dat$Utilities == "AllPub"] <- 1
r_dat$Utilities<-as.numeric(r_dat$Utilities)
#La propiedas normalmente están en llano o en pequeña cuesta, el resto indicamos cero esta propiedad.
r_dat$LandSlope[r_dat$LandSlope != "Gtl"] <- 0
r_dat$LandSlope[r_dat$LandSlope == "Gtl"] <- 1
r_dat$LandSlope<-as.numeric(r_dat$LandSlope)
#Tomamos como valor estandar de tipo de calefacción GasA
r_dat$Heating[r_dat$Heating != "GasA"] <- 0
r_dat$Heating[r_dat$Heating == "GasA"] <- 1
r_dat$Heating<-as.numeric(r_dat$Heating)
#Si tienen aire acondiciones lo indicamos como 1
r_dat$CentralAir[r_dat$CentralAir != "Y"] <- 0
r_dat$CentralAir[r_dat$CentralAir == "Y"] <- 1
r_dat$CentralAir<-as.numeric(r_dat$CentralAir)
#Tomamos como valor instalación electrica estandard
r_dat$Electrical[r_dat$Electrical != "SBrkr"] <- 0
r_dat$Electrical[r_dat$Electrical == "SBrkr"] <- 1
r_dat$Electrical<-as.numeric(r_dat$Electrical)
#Tomamos como valor la funcionalidad típica de la casa
r_dat$Functional[r_dat$Functional != "Typ"] <- 0
r_dat$Functional[r_dat$Functional == "Typ"] <- 1
r_dat$Functional<-as.numeric(r_dat$Functional)
#Tomamos que como valor principal para la mayoría que tienen el acceso pavimentado
r_dat$PavedDrive[r_dat$PavedDrive != "Y"] <- 0
r_dat$PavedDrive[r_dat$PavedDrive == "Y"] <- 1
r_dat$PavedDrive<-as.numeric(r_dat$PavedDrive)
#Tipo de venta WD Warranty Deed
r_dat$SaleType[r_dat$SaleType != "Y"] <- 0
r_dat$SaleType[r_dat$SaleType == "Y"] <- 1
r_dat$SaleType<-as.numeric(r_dat$SaleType)
#Condiciones de venta normales
r_dat$SaleCondition[r_dat$SaleCondition != "Normal"] <- 0
r_dat$SaleCondition[r_dat$SaleCondition == "Normal"] <- 1
r_dat$SaleCondition<-as.numeric(r_dat$SaleCondition)
#estilo de tejado tomamos Grable como el estandar
r_dat$RoofStyle[r_dat$RoofStyle != "Normal"] <- 0
r_dat$RoofStyle[r_dat$RoofStyle == "Normal"] <- 1
r_dat$RoofStyle<-as.numeric(r_dat$RoofStyle)
#Elimino estas variables por ser o bien repetitivas o no aportar a la valoración por tener poca variedad de valores.
r_dat<- r_dat[,!colnames(r_dat)=="Condition2"]
r_dat<- r_dat[,!colnames(r_dat)=="RoofMatl"]
r_dat<- r_dat[,!colnames(r_dat)=="Exterior2nd"]
return(r_dat)
}
Vamos a generar variables dicotómicas, (dummy) para algunas de las variables categoricas que tenemos, para ello usaremos la librería dummies. Como hemos hecho en el resto de ocasiones lo encapsulamos en una función:
createDummies <- function(data){
r_dat <-data
r_dat <- dummy.data.frame(r_dat,r_dat$LotConfig,sep=".")
r_dat <- dummy.data.frame(r_dat,'LotConfig',sep=".")
r_dat <- dummy.data.frame(r_dat,"Neighborhood",sep=".")
r_dat <- dummy.data.frame(r_dat,"Condition1",sep=".")
r_dat <- dummy.data.frame(r_dat,"MasVnrType",sep=".")
r_dat <- dummy.data.frame(r_dat,"BldgType",sep=".")
r_dat <- dummy.data.frame(r_dat,"HouseStyle",sep=".")
r_dat <- dummy.data.frame(r_dat,"Exterior1st",sep=".")
r_dat <- dummy.data.frame(r_dat,"GarageType",sep=".")
#Eliminamos el la columna none ya que fue el valor que le dimos a los NA
r_dat<- r_dat[,!colnames(r_dat)=="GarageType.None"]
r_dat <- dummy.data.frame(r_dat,"Foundation",sep=".")
#GarageType = none hay que eliminarla
return(r_dat)
}
Vamos a incluir en una función todas las transformaciones para ser llamadas desde un único punto.
doAllTrans <- function (data,test){
r_dat <- data
r_dat<-missingValues(r_dat)
r_dat<-delOutliers(r_dat,test)
r_dat<-ordinals(r_dat)
r_dat<- simplyTransforms(r_dat)
r_dat<- createDummies(r_dat)
#quitamos la variable id
r_dat<- r_dat[,!colnames(r_dat)=="Id"]
return(r_dat)
}
aux_data <- dat_train
aux_data<-doAllTrans(aux_data,FALSE)
Ya tenemos el dataset preparado para ejecutar el modelo. Vamos a dividirlo en dos partes una para entrenamiento y otra para test. Hemos divido en un 50% para cada uno ya que teníamos problemas de rango en el momento de la evaluación con Rmse, debido a que nuestro dataset no tiene muchos datos pero si muchas variables.
salePrice <- aux_data$SalePrice
partition <- createDataPartition(y=salePrice,
p=.5,
list=F)
train_aux <- aux_data[partition,]
test_aux <- aux_data[-partition,]
Vamos a implementar un modelo de Regresión Líneal Multivariable.
lm_model_1 <- lm(SalePrice ~ ., data=train_aux)
summary(lm_model_1)
##
## Call:
## lm(formula = SalePrice ~ ., data = train_aux)
##
## Residuals:
## Min 1Q Median 3Q Max
## -126297 -10228 -412 9814 98190
##
## Coefficients: (15 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.394e+06 1.376e+06 -1.739 0.082531 .
## MSSubClass -2.224e+02 1.099e+02 -2.025 0.043343 *
## MSZoning -8.114e+02 3.974e+03 -0.204 0.838264
## LotFrontage 2.891e+00 2.955e+01 0.098 0.922102
## LotArea 4.506e-01 1.029e-01 4.377 1.42e-05 ***
## Street 3.708e+04 1.770e+04 2.095 0.036588 *
## LotShape 4.916e+03 2.162e+03 2.274 0.023332 *
## LandContour -6.694e+03 3.724e+03 -1.798 0.072744 .
## Utilities 4.501e+04 2.748e+04 1.638 0.101928
## LotConfig.Corner 8.561e+02 2.300e+03 0.372 0.709819
## LotConfig.CulDSac 1.448e+04 3.710e+03 3.902 0.000106 ***
## LotConfig.FR2 -1.634e+03 5.208e+03 -0.314 0.753792
## LotConfig.FR3 -1.090e+04 1.571e+04 -0.694 0.488175
## LotConfig.Inside NA NA NA NA
## LandSlope -3.017e+03 4.970e+03 -0.607 0.544072
## Neighborhood.Blmngtn -3.047e+04 1.650e+04 -1.847 0.065273 .
## Neighborhood.Blueste -3.071e+04 2.582e+04 -1.190 0.234693
## Neighborhood.BrDale 5.277e+03 1.722e+04 0.306 0.759432
## Neighborhood.BrkSide -1.896e+04 1.501e+04 -1.263 0.207135
## Neighborhood.ClearCr -2.366e+04 1.513e+04 -1.564 0.118435
## Neighborhood.CollgCr -3.157e+04 1.385e+04 -2.280 0.022966 *
## Neighborhood.Crawfor 8.613e+02 1.464e+04 0.059 0.953094
## Neighborhood.Edwards -2.791e+04 1.430e+04 -1.952 0.051368 .
## Neighborhood.Gilbert -3.090e+04 1.425e+04 -2.169 0.030504 *
## Neighborhood.IDOTRR -3.234e+04 1.588e+04 -2.037 0.042126 *
## Neighborhood.MeadowV -5.392e+03 1.816e+04 -0.297 0.766663
## Neighborhood.Mitchel -2.550e+04 1.454e+04 -1.754 0.079910 .
## Neighborhood.NAmes -2.787e+04 1.391e+04 -2.003 0.045604 *
## Neighborhood.NoRidge -6.223e+03 1.466e+04 -0.424 0.671395
## Neighborhood.NPkVill 1.105e+04 1.808e+04 0.611 0.541565
## Neighborhood.NridgHt 4.282e+03 1.415e+04 0.303 0.762328
## Neighborhood.NWAmes -2.948e+04 1.437e+04 -2.052 0.040641 *
## Neighborhood.OldTown -2.618e+04 1.503e+04 -1.742 0.082110 .
## Neighborhood.Sawyer -2.012e+04 1.412e+04 -1.425 0.154700
## Neighborhood.SawyerW -3.343e+04 1.439e+04 -2.322 0.020546 *
## Neighborhood.Somerst -1.573e+04 1.444e+04 -1.089 0.276547
## Neighborhood.StoneBr 6.773e+03 1.479e+04 0.458 0.647182
## Neighborhood.SWISU -2.316e+04 1.602e+04 -1.445 0.148877
## Neighborhood.Timber -2.652e+04 1.485e+04 -1.786 0.074641 .
## Neighborhood.Veenker NA NA NA NA
## Condition1.Artery -2.487e+04 1.940e+04 -1.282 0.200295
## Condition1.Feedr -2.053e+04 1.892e+04 -1.085 0.278225
## Condition1.Norm -1.177e+04 1.871e+04 -0.629 0.529476
## Condition1.PosA 1.561e+03 2.189e+04 0.071 0.943158
## Condition1.PosN -1.456e+04 2.013e+04 -0.724 0.469611
## Condition1.RRAe -3.993e+04 2.104e+04 -1.898 0.058156 .
## Condition1.RRAn -5.760e+03 2.064e+04 -0.279 0.780273
## Condition1.RRNe NA NA NA NA
## Condition1.RRNn NA NA NA NA
## BldgType.1Fam 6.157e+03 1.205e+04 0.511 0.609668
## BldgType.2fmCon 2.891e+04 1.087e+04 2.661 0.008006 **
## BldgType.Duplex 4.603e+03 1.138e+04 0.404 0.686132
## BldgType.Twnhs -1.440e+04 6.614e+03 -2.178 0.029802 *
## BldgType.TwnhsE NA NA NA NA
## HouseStyle.1.5Fin -8.681e+03 7.088e+03 -1.225 0.221165
## HouseStyle.1.5Unf -8.590e+03 1.082e+04 -0.794 0.427556
## HouseStyle.1Story -1.085e+04 8.089e+03 -1.342 0.180195
## HouseStyle.2.5Fin -2.195e+04 1.691e+04 -1.298 0.194801
## HouseStyle.2.5Unf -2.458e+04 1.531e+04 -1.606 0.108798
## HouseStyle.2Story -1.201e+04 7.007e+03 -1.714 0.087016 .
## HouseStyle.SFoyer -1.055e+04 7.565e+03 -1.394 0.163850
## HouseStyle.SLvl NA NA NA NA
## OverallQual 8.873e+03 1.266e+03 7.008 6.59e-12 ***
## OverallCond 6.928e+03 1.134e+03 6.109 1.82e-09 ***
## YearBuilt 4.421e+02 9.340e+01 4.734 2.76e-06 ***
## YearRemodAdd 6.979e+01 7.258e+01 0.961 0.336711
## RoofStyle NA NA NA NA
## Exterior1st.AsbShng 8.354e+03 1.079e+04 0.774 0.439159
## Exterior1st.AsphShn NA NA NA NA
## Exterior1st.BrkComm -4.573e+04 2.333e+04 -1.960 0.050412 .
## Exterior1st.BrkFace 9.821e+03 8.609e+03 1.141 0.254413
## Exterior1st.CBlock NA NA NA NA
## Exterior1st.CemntBd 4.528e+03 8.974e+03 0.505 0.614015
## Exterior1st.HdBoard -3.632e+03 7.581e+03 -0.479 0.632033
## Exterior1st.ImStucc -1.882e+04 2.343e+04 -0.803 0.422030
## Exterior1st.MetalSd 6.505e+03 7.380e+03 0.882 0.378387
## Exterior1st.Plywood -6.670e+03 7.948e+03 -0.839 0.401639
## Exterior1st.Stone -5.291e+03 2.504e+04 -0.211 0.832738
## Exterior1st.Stucco 1.504e+04 9.987e+03 1.506 0.132685
## Exterior1st.VinylSd 2.452e+03 7.342e+03 0.334 0.738482
## `Exterior1st.Wd Sdng` 8.683e+02 7.327e+03 0.118 0.905717
## Exterior1st.WdShing NA NA NA NA
## MasVnrType.BrkCmn -1.918e+04 8.738e+03 -2.195 0.028519 *
## MasVnrType.BrkFace -3.472e+03 3.677e+03 -0.944 0.345369
## MasVnrType.None 1.730e+03 3.842e+03 0.450 0.652733
## MasVnrType.Stone NA NA NA NA
## MasVnrArea 1.486e+01 6.794e+00 2.188 0.029061 *
## ExterQual 1.147e+04 2.695e+03 4.256 2.41e-05 ***
## ExterCond -7.037e+03 2.879e+03 -2.444 0.014818 *
## Foundation.BrkTil 6.176e+03 1.712e+04 0.361 0.718456
## Foundation.CBlock 1.264e+04 1.676e+04 0.754 0.450968
## Foundation.PConc 1.407e+04 1.679e+04 0.839 0.402077
## Foundation.Slab 2.111e+04 1.954e+04 1.080 0.280371
## Foundation.Stone -1.260e+03 2.885e+04 -0.044 0.965173
## Foundation.Wood NA NA NA NA
## BsmtQual 1.722e+03 2.204e+03 0.781 0.435058
## BsmtCond -3.857e+03 2.655e+03 -1.453 0.146836
## BsmtExposure 4.097e+03 1.157e+03 3.541 0.000430 ***
## BsmtFinType1 4.615e+02 6.738e+02 0.685 0.493660
## BsmtFinSF1 2.881e+01 7.012e+00 4.108 4.55e-05 ***
## BsmtFinType2 -3.576e+02 1.867e+03 -0.192 0.848194
## BsmtFinSF2 1.374e+01 1.234e+01 1.113 0.266104
## BsmtUnfSF 1.223e+01 6.187e+00 1.977 0.048502 *
## TotalBsmtSF NA NA NA NA
## Heating -5.598e+03 7.249e+03 -0.772 0.440268
## HeatingQC 8.281e+02 1.268e+03 0.653 0.513905
## CentralAir -8.188e+02 4.679e+03 -0.175 0.861133
## Electrical -4.619e+03 3.723e+03 -1.241 0.215263
## `1stFlrSF` 5.631e+01 7.239e+00 7.779 3.25e-14 ***
## `2ndFlrSF` 5.879e+01 8.118e+00 7.243 1.37e-12 ***
## LowQualFinSF -8.162e+00 2.338e+01 -0.349 0.727165
## GrLivArea NA NA NA NA
## BsmtFullBath 4.023e+03 2.668e+03 1.508 0.132190
## BsmtHalfBath -1.957e+03 4.671e+03 -0.419 0.675307
## FullBath 1.162e+02 3.008e+03 0.039 0.969208
## HalfBath 7.436e+02 2.690e+03 0.276 0.782361
## BedroomAbvGr -1.940e+03 1.737e+03 -1.117 0.264543
## KitchenAbvGr -6.125e+03 7.284e+03 -0.841 0.400771
## KitchenQual 5.348e+03 2.094e+03 2.554 0.010887 *
## TotRmsAbvGrd 1.109e+02 1.269e+03 0.087 0.930392
## Functional 1.235e+04 4.030e+03 3.065 0.002278 **
## Fireplaces 4.412e+03 2.763e+03 1.597 0.110908
## FireplaceQu 3.262e+02 1.046e+03 0.312 0.755254
## GarageType.2Types 7.833e+04 1.583e+05 0.495 0.620933
## GarageType.Attchd 1.108e+05 1.592e+05 0.696 0.486864
## GarageType.Basment 1.081e+05 1.588e+05 0.681 0.496374
## GarageType.BuiltIn 1.119e+05 1.596e+05 0.701 0.483351
## GarageType.CarPort 1.200e+05 1.592e+05 0.754 0.451432
## GarageType.Detchd 1.175e+05 1.593e+05 0.737 0.461117
## GarageYrBlt -7.630e+01 8.365e+01 -0.912 0.362068
## GarageFinish 2.971e+03 1.645e+03 1.806 0.071378 .
## GarageCars 7.026e+03 2.889e+03 2.432 0.015304 *
## GarageArea 2.287e+00 1.023e+01 0.224 0.823185
## GarageQual 5.930e+03 5.134e+03 1.155 0.248499
## GarageCond -4.114e+02 5.175e+03 -0.080 0.936659
## PavedDrive -1.356e+03 3.671e+03 -0.369 0.711981
## WoodDeckSF 1.796e+01 8.133e+00 2.208 0.027611 *
## OpenPorchSF 8.027e+00 1.453e+01 0.553 0.580701
## EnclosedPorch 5.673e+00 1.658e+01 0.342 0.732328
## `3SsnPorch` 3.272e+01 2.467e+01 1.326 0.185251
## ScreenPorch 2.547e+00 1.587e+01 0.160 0.872586
## PoolArea 1.865e+01 1.950e+01 0.957 0.339104
## MiscVal -3.660e-01 1.240e+00 -0.295 0.768078
## MoSold -2.106e+02 3.234e+02 -0.651 0.515104
## YrSold 6.388e+02 6.700e+02 0.953 0.340792
## SaleType NA NA NA NA
## SaleCondition -2.777e+03 2.476e+03 -1.122 0.262471
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 20940 on 594 degrees of freedom
## Multiple R-squared: 0.9313, Adjusted R-squared: 0.9161
## F-statistic: 61.46 on 131 and 594 DF, p-value: < 2.2e-16
Tenemos una aproximación muy buena, ya que multiple R-Squared está cerca de 1. Vamos a probar si lo mejoramos dejando sólo los que tienen 3 *, es decir para los que los p-valores son inferiores a 0.05, en nuestro caso incluso menos al tomar sólo los de 3 asteriscos, se supone que son los mejores. Incluyo GrLivArea y TotalBsmtSF, aunque parece que han sido eliminadas debido a la multicolinealidad, pero vamos a insistir y las mantenemos para ver si al eliminar variables se vuelven más representativas:
lm_model_2 <- lm(SalePrice ~ LotArea+ OverallQual+ OverallCond+ YearBuilt+ ExterQual+ BsmtExposure+ BsmtFinSF1+ BsmtUnfSF+ TotalBsmtSF + `1stFlrSF`+`2ndFlrSF` + GrLivArea+ Functional, data=train_aux)
summary(lm_model_2)
##
## Call:
## lm(formula = SalePrice ~ LotArea + OverallQual + OverallCond +
## YearBuilt + ExterQual + BsmtExposure + BsmtFinSF1 + BsmtUnfSF +
## TotalBsmtSF + `1stFlrSF` + `2ndFlrSF` + GrLivArea + Functional,
## data = train_aux)
##
## Residuals:
## Min 1Q Median 3Q Max
## -111926 -15451 -245 13949 136589
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -9.239e+05 9.437e+04 -9.789 < 2e-16 ***
## LotArea 5.564e-01 9.761e-02 5.700 1.76e-08 ***
## OverallQual 1.241e+04 1.264e+03 9.815 < 2e-16 ***
## OverallCond 6.723e+03 9.818e+02 6.847 1.63e-11 ***
## YearBuilt 3.860e+02 4.902e+01 7.875 1.27e-14 ***
## ExterQual 2.425e+04 2.594e+03 9.348 < 2e-16 ***
## BsmtExposure 3.951e+03 1.086e+03 3.640 0.000293 ***
## BsmtFinSF1 2.291e+01 6.559e+00 3.493 0.000507 ***
## BsmtUnfSF -3.251e-01 6.430e+00 -0.051 0.959695
## TotalBsmtSF 1.074e+01 7.489e+00 1.434 0.152148
## `1stFlrSF` 9.081e+01 2.052e+01 4.426 1.11e-05 ***
## `2ndFlrSF` 7.361e+01 2.039e+01 3.610 0.000328 ***
## GrLivArea -1.737e+01 1.995e+01 -0.870 0.384412
## Functional 1.064e+04 4.237e+03 2.511 0.012260 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 25980 on 712 degrees of freedom
## Multiple R-squared: 0.8733, Adjusted R-squared: 0.8709
## F-statistic: 377.4 on 13 and 712 DF, p-value: < 2.2e-16
No es malo, pero parece que no hemos mejorado el modelo, en esta ocasión el valor de R-squared = 0.86, que es inferior al que teníamos antes. Esto puede ser debido a que alguna de las variables que tienen sólo dos estrellas tiene importancia. Vamos a usar el primer modelo ya que es una aproximación muy buena.
Vamos a realizar una predicción con el modelo y los datos de test que hemos extraido con la liabrería caret:
prediction <- predict(lm_model_1, test_aux, type="response")
## Warning in predict.lm(lm_model_1, test_aux, type = "response"): prediction
## from a rank-deficient fit may be misleading
Este warning se debe a que nuestro dataset no es muy grande y teniendo en cuenta que lo hemos dividido en dos y tenemos un grán número de variables lo que hace que el rango no sea muy bueno. Vamos a revisar el Error Cuadratico Medio:
model_output <- cbind(test_aux, prediction)
model_output$log_prediction <- log(model_output$prediction)
model_output$log_SalePrice <- log(model_output$SalePrice)
rmse(model_output$log_SalePrice,model_output$log_prediction)
## [1] 0.1653317
Vemos que el valor del Error Cuadratico Medio es bajo.
Vamos a dibujar un qqplot para ver como se ajusta nuestro modelo.
residuos <- rstandard(lm_model_1)
qqnorm(residuos)
qqline(residuos)
Para una mayoría de los valores se ajusta a la recta o muy cerca de la recta, pero en los estremos tiende a alejarse.