#cargado librerias
library(dplyr)
library(caret)

Primera parte

caso: brazilian_houses_to_rent

Descripcion: Este conjunto de datos contiene 10,692 propiedades para alquilar en cinco ciudades de brazil con 13 características diferentes

  • city: Ciudad donde se encuentra la propiedad

  • area: Área de la propiedad

  • rooms: Cantidad de habitaciones

  • bathroom: Cantidad de baños

  • parking spaces: Cantidad de plazas de estacionamiento

  • floor: Piso

  • animal: si acepta animales o no

  • furniture: amoblado o no

  • hoa: impuesto de la comunidad de propietarios

  • rent amount: monto del alquiler

  • property tax: impuesto predial municipal

  • fire insurance: valor del seguro de incendio

  • total: la suma de todos los valores

  • Target: rent amount

Contexto del problema:

Predicir el precio de alquiler de una vivienda en 05 ciudades de Brazil en base al area de la propiedad.

Las variables a ser utilizadas:

  • area: variable predictora

  • rent amount: variable respuesta

Fuente de datos en: https://www.kaggle.com/datasets/rubenssjr/brasilian-houses-to-rent.

1. Estimar el modelo de regresión lineal simple usando todo el dataset. Obtener los gráficos de residuales y comentar.

1.1 Exploración de datos

#cargando los datos
df_HouseTR= read.csv('houses_to_rent_v2.csv',check.names=FALSE)
head(df_HouseTR,5)
#dimensiones del dataset
print(dim(df_HouseTR))
## [1] 10692    13
#renombrando nombre de las variables
df_HouseTR <- df_HouseTR %>% 
  rename(
    'parkingspaces'='parking spaces',
    'hoa' = 'hoa (R$)',
    'rentamount' ='rent amount (R$)',
    'propertytax'='property tax (R$)',
    'fireinsurance'='fire insurance (R$)',
    'total'='total (R$)')
#revisando los tipos de variables
str(df_HouseTR)
## 'data.frame':    10692 obs. of  13 variables:
##  $ city         : chr  "São Paulo" "São Paulo" "Porto Alegre" "Porto Alegre" ...
##  $ area         : int  70 320 80 51 25 376 72 213 152 35 ...
##  $ rooms        : int  2 4 1 2 1 3 2 4 2 1 ...
##  $ bathroom     : int  1 4 1 1 1 3 1 4 2 1 ...
##  $ parkingspaces: int  1 0 1 0 0 7 0 4 1 0 ...
##  $ floor        : chr  "7" "20" "6" "2" ...
##  $ animal       : chr  "acept" "acept" "acept" "acept" ...
##  $ furniture    : chr  "furnished" "not furnished" "not furnished" "not furnished" ...
##  $ hoa          : int  2065 1200 1000 270 0 0 740 2254 1000 590 ...
##  $ rentamount   : int  3300 4960 2800 1112 800 8000 1900 3223 15000 2300 ...
##  $ propertytax  : int  211 1750 0 22 25 834 85 1735 250 35 ...
##  $ fireinsurance: int  42 63 41 17 11 121 25 41 191 30 ...
##  $ total        : int  5618 7973 3841 1421 836 8955 2750 7253 16440 2955 ...
#creado dataframe con las variables en estudio
df_Htor=select(df_HouseTR,area, rentamount)
#Analizando grafico de dispersión
plot(sqrt(df_Htor$area),sqrt(df_Htor$rentamount))

1.2 Analisis de outliers

#analisando outliers
par(mfrow=c(1,2))
boxplot(df_Htor$area, main='area')
boxplot(df_Htor$rentamount, main='rentamount')

#describe: area y rentamount
summary(df_Htor)
##       area           rentamount   
##  Min.   :   11.0   Min.   :  450  
##  1st Qu.:   56.0   1st Qu.: 1530  
##  Median :   90.0   Median : 2661  
##  Mean   :  149.2   Mean   : 3896  
##  3rd Qu.:  182.0   3rd Qu.: 5000  
##  Max.   :46335.0   Max.   :45000
#analizando valore ourlier por percentiles: variable area
quantile(df_Htor$area, seq(.75,1,.01))
##      75%      76%      77%      78%      79%      80%      81%      82% 
##   182.00   190.00   200.00   200.00   208.00   215.00   220.00   230.00 
##      83%      84%      85%      86%      87%      88%      89%      90% 
##   240.00   250.00   250.00   263.26   276.00   288.08   300.00   300.00 
##      91%      92%      93%      94%      95%      96%      97%      98% 
##   320.00   340.00   353.00   380.00   400.00   429.36   472.54   530.00 
##      99%     100% 
##   650.09 46335.00
#valor maximo admitido (percentil 99) - se perdera el 1% de los datos
area_max=650.09
df_Htor=df_Htor[df_Htor$area<=area_max,]
#Boxplot: analisando outliers
par(mfrow=c(1,2))
boxplot(df_Htor$area, main='area')
boxplot(df_Htor$rentamount, main='rentamount')

1.3 Transformación de variables

#Realizando conversion de las variables aplicando logaritmo
df_Htor$area=log(df_Htor$area)
df_Htor$rentamount=log(df_Htor$rentamount)
#Boxplot:
par(mfrow=c(1,2))
boxplot(df_Htor$area, main='area')
boxplot(df_Htor$rentamount, main='rentamount')

#Analizando grafico de dispersión nuevamente
plot(df_Htor$area,df_Htor$rentamount)

1.4 Coeficientes de correlacion

cor(df_Htor$area, df_Htor$rentamount, method = "pearson")
## [1] 0.7214561
cor(df_Htor$area, df_Htor$rentamount, method = "spearman")
## [1] 0.7224891

1.5 Desarollo del modelo de regresión simple

ml_rent <- lm(rentamount ~ area, data = df_Htor)
summary(ml_rent)
## 
## Call:
## lm(formula = rentamount ~ area, data = df_Htor)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.9579 -0.3992 -0.0260  0.3657  2.3071 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 4.589232   0.031665   144.9   <2e-16 ***
## area        0.727847   0.006791   107.2   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.5412 on 10583 degrees of freedom
## Multiple R-squared:  0.5205, Adjusted R-squared:  0.5205 
## F-statistic: 1.149e+04 on 1 and 10583 DF,  p-value: < 2.2e-16
plot(df_Htor$area,df_Htor$rentamount)
abline(ml_rent, col="red", lwd=2)

1.6 Gráficos de residuales

par(mfrow = c(2, 2))
plot(ml_rent)

1.7 Comentarios

Residual vs Fitted (linealidad)

  • Podemos observar en este grafico de correlacion que existe un patron o tendencia identificable, de modo que no podemos corroborar el supuesto de linealidad

Normal Q-Q (normalidad)

  • No se observa una buena aproximación a la normalidad. No obstante, para ser mas rigurosos podemos recurrir a pruebas de normalidad, como la prueba Kolmogorov-Smirnov

Scale - Location (homocedasticidad)

  • El grafico nos permite observar una apariencia de un mayor grosor de la nube de puntos en una dirección, lo cual no permite aceptar el supuesto de varianza constante de los residuos

Residual vs Leverage (datos alejados)

  • Se observalores valores influyentes: 7749, 6948

2. Seleccionar un conjunto de entrenamiento del 70% usando set.seed(7345). Evaluar el modelo de regresión estimado usando el conjunto de prueba y los indicadores correspondientes.

2.1 creando la particion

RNGkind(sample.kind = "Rejection")
set.seed(7345)
ind.train <- createDataPartition(y = df_Htor$rentamount, p = 0.70, list = FALSE)
data.train <- df_Htor[ind.train, ]
data.test <- df_Htor[-ind.train, ]

2.1 Desarrollando el modelo

ctrl <- trainControl(method = 'none')
ml_rent2 <- train(rentamount ~ area, data = data.train, method = 'lm',
            trControl = ctrl)

2.2 Evaluación del modelo

ml_rent2
## Linear Regression 
## 
## 7411 samples
##    1 predictor
## 
## No pre-processing
## Resampling: None
ml_rent2.pred <- predict(ml_rent2, newdata = data.test)
postResample(ml_rent2.pred, data.test$rentamount)
##      RMSE  Rsquared       MAE 
## 0.5372819 0.5243059 0.4357497

Segunda parte

Presentar dos variantes del método de gradiente descendiente. Presente un ejemplo de aplicación usando R o Python usando el conjunto de datos elegido en la primera parte.

Variantes del método de gradiente descendiente

Existen tres tipos de gradiente descendiente:

  • Batch Gradient Descent
  • Mini-batch Gradient Descent
  • Stochastic Gradient Descent

Batch Gradient Descent

En Batch Gradient Descent, todos los datos de entrenamiento se tienen en cuenta para dar un solo paso. Tomamos el promedio de las gradientes de todos los ejemplos de entrenamiento y luego usamos esa gradiente media para actualizar nuestros parámetros. Eso es solo un paso de descenso de gradiente en una época.

Batch Gradient Descent es ideal para variedades de error convexas o relativamente suaves. En este caso, nos movemos algo directamente hacia una solución óptima.

El gráfico de costo frente a épocas también es bastante suave porque estamos promediando todos los gradientes de datos de entrenamiento para un solo paso. El costo sigue disminuyendo a lo largo de las épocas.

Mini-batch Gradient Descent

calcula el gradiente a partir de un pequeño subconjunto aleatorio de muestras llamadas mini-batches y no a partir de todo el conjunto de entrenamiento ni a partir de una única muestra. Normalmente, este algoritmo tarda menos en alcanzar el mínimo que Batch Gradient Descent pero corre el riesgo de caer en un mínimo local y no ser capaz de salir de él. El valor n suele denominarse batch size.

Por lo tanto, cuando usamos el descenso de gradiente de mini lotes, actualizamos nuestros parámetros con frecuencia y podemos usar la implementación vectorizada para cálculos más rápidos.

Ejemplo de aplicación para Batch Gradient Descent

 gradientDesc <- function(x, y, learn_rate, conv_threshold, n, max_iter) {
  plot(x, y, col = "blue", pch = 20)
  m <- runif(1, 0, 1)
  c <- runif(1, 0, 1)
  yhat <- m * x + c
  MSE <- sum((y - yhat) ^ 2) / n
  converged = F
  iterations = 0
  while(converged == F) {
    ## Implement the gradient descent algorithm
    m_new <- m - learn_rate * ((1 / n) * (sum((yhat - y) * x)))
    c_new <- c - learn_rate * ((1 / n) * (sum(yhat - y)))
    m <- m_new
    c <- c_new
    yhat <- m * x + c
    MSE_new <- sum((y - yhat) ^ 2) / n
    if(MSE - MSE_new <= conv_threshold) {
      abline(c, m) 
      converged = T
      return(paste("Optimal intercept:", c, "Optimal slope:", m))
    }
    iterations = iterations + 1
    if(iterations > max_iter) { 
      abline(c, m) 
      converged = T
      return(paste("Optimal intercept:", c, "Optimal slope:", m))
    }
  }
}
gradientDesc(df_Htor$area, df_Htor$rentamount, 0.0000293, 0.001, 32, 100000)

## [1] "Optimal intercept: 4.58923244569354 Optimal slope: 0.727847232666991"

Comparacion