Descripción del problema

Maria comenzó como agente de bienes raíces en Cali hace 10 años. Después de laborar dos años para una empresa nacional, se traslado a Bogotá y trabajó para otra agencia de bienes raíces. Sus amigos y familiares la convencieron de que con su experiencia y conocimientos del negocio debía abrir su propia agencia. Terminó por adquirir la licencia de intermediario y al poco tiempo fundó su propia compañía, C&A (Casas y Apartamentos) en Cali. Santiago y Lina, dos vendedores de la empresa anterior aceptaron trabajar en la nueva compaña. En la actualidad ocho agentes de bienes raíces colaboran con ella en C&A.

Actualmente las ventas de bienes raíces en Cali se han visto disminuidas de manera significativa en lo corrido del año. Durante este periodo muchas instituciones bancarias de ahorro y vivienda están prestando grandes sumas de dinero para la industria y la construcción comercial y residencial. Cuando el efecto producto de las tensiones políticas y sociales disminuya, se espera que la actividad económica de este sector se reactive.

Hace dos días, María recibió una carta solicitando asesoría para la compra de dos viviendas por parte de una compañía internacional que desea ubicar a dos de sus empleados con sus familias en la ciudad. Las solicitudes incluyen las siguientes condiciones:

Características Vivienda 1 Vivienda 2
Tipo Casa Apartamento
área construida 200 300
parqueaderos 1 3
baños 2 3
habitaciones 4 5
estrato 4 o 5 5 o 6
zona Norte Sur
crédito preaprobado 350 millones 850 millones

Conociendo el set de datos

# devtools::install_github("dgonxalex80/paqueteMODELOS", force = TRUE)
library(paqueteMODELOS)
vivienda
## # A tibble: 8,322 × 13
##       id zona   piso  estrato preciom areaconst parqueaderos banios habitaciones
##    <dbl> <chr>  <chr>   <dbl>   <dbl>     <dbl>        <dbl>  <dbl>        <dbl>
##  1  1147 Zona … <NA>        3     250        70            1      3            6
##  2  1169 Zona … <NA>        3     320       120            1      2            3
##  3  1350 Zona … <NA>        3     350       220            2      2            4
##  4  5992 Zona … 02          4     400       280            3      5            3
##  5  1212 Zona … 01          5     260        90            1      2            3
##  6  1724 Zona … 01          5     240        87            1      3            3
##  7  2326 Zona … 01          4     220        52            2      2            3
##  8  4386 Zona … 01          5     310       137            2      3            4
##  9  1209 Zona … 02          5     320       150            2      4            6
## 10  1592 Zona … 02          5     780       380            2      3            3
## # ℹ 8,312 more rows
## # ℹ 4 more variables: tipo <chr>, barrio <chr>, longitud <dbl>, latitud <dbl>
df <- data.frame(vivienda)

A continuación se inicia con la exploración del conjunto de datos

¿Cuál es el número de registros y cuál es la cantidad de atributos?

cant_reg <- nrow(df)
cant_atr <- ncol(df)

cat("Cantidad de Registros: ", cant_reg, "\n")
## Cantidad de Registros:  8322
cat("Cantidad de Atributos: ", cant_atr, "\n")
## Cantidad de Atributos:  13

Tipo de dato de los atributos

str(df)
## 'data.frame':    8322 obs. of  13 variables:
##  $ id          : num  1147 1169 1350 5992 1212 ...
##  $ zona        : chr  "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : chr  NA NA NA "02" ...
##  $ estrato     : num  3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num  250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num  70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num  1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num  3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num  6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr  "Casa" "Casa" "Casa" "Casa" ...
##  $ barrio      : chr  "20 de julio" "20 de julio" "20 de julio" "3 de julio" ...
##  $ longitud    : num  -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num  3.43 3.43 3.44 3.44 3.46 ...

Valores únicos de las variables categóricas.

cat("Zona:\n")
## Zona:
print(unique(df$zona))
## [1] "Zona Oriente" "Zona Sur"     "Zona Norte"   "Zona Oeste"   "Zona Centro" 
## [6] NA
cat("\n")
cat("Piso:\n")
## Piso:
print(unique(df$piso))
##  [1] NA   "02" "01" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12"
cat("\n")
cat("Tipo:\n")
## Tipo:
print(unique(df$tipo))
## [1] "Casa"        "Apartamento" NA
cat("\n")
cat("Barrio:\n")
## Barrio:
print(unique(df$barrio))
##   [1] "20 de julio"                   "3 de julio"                   
##   [3] "acopi"                         "agua blanca"                  
##   [5] "aguablanca"                    "aguacatal"                    
##   [7] "alameda"                       "alameda del río"              
##   [9] "alameda del rio"               "alamos"                       
##  [11] "alborada"                      "alcazares"                    
##  [13] "alférez real"                 "alferez real"                 
##  [15] "alfonso lópez"                 "alfonso lópez i"              
##  [17] "alfonso lopez"                 "alto jordán"                  
##  [19] "altos de guadalupe"            "altos de menga"               
##  [21] "altos de santa"                "antonio nariño"               
##  [23] "aranjuez"                      "arboleda"                     
##  [25] "arboleda campestre candelaria" "arboledas"                    
##  [27] "atanasio girardot"             "autopista sur"                
##  [29] "bajo aguacatal"                "barranquilla"                 
##  [31] "barrio 7de agosto"             "barrio el recuerdo"           
##  [33] "barrio eucarístico"            "barrio obrero"                
##  [35] "barrio tranquilo y"            "base aérea"                  
##  [37] "belalcazar"                    "Belalcazar"                   
##  [39] "belisario caicedo"             "bella suiza"                  
##  [41] "bella suiza alta"              "bellavista"                   
##  [43] "benjamín herrera"              "berlin"                       
##  [45] "bloques del limonar"           "bochalema"                    
##  [47] "bolivariano"                   "bosques de alboleda"          
##  [49] "bosques del limonar"           "boyacá"                       
##  [51] "bretaña"                       "brisas de guadalupe"          
##  [53] "brisas de los"                 "Brisas De Los"                
##  [55] "brisas del guabito"            "brisas del limonar"           
##  [57] "Bueno Madrid"                  "buenos aires"                 
##  [59] "cañasgordas"                   "cañaveralejo"                 
##  [61] "cañaverales"                   "cañaverales los samanes"      
##  [63] "caldas"                        "Cali"                         
##  [65] "cali bella"                    "cali canto"                   
##  [67] "calibella"                     "calicanto"                    
##  [69] "calicanto viii"                "calima"                       
##  [71] "calimio norte"                 "calipso"                      
##  [73] "cambulos"                      "camino real"                  
##  [75] "Camino Real"                   "campestre"                    
##  [77] "caney"                         "caney especial"               
##  [79] "capri"                         "cascajal"                     
##  [81] "cataya real"                   "ceibas"                       
##  [83] "centelsa"                      "centenario"                   
##  [85] "Centenario"                    "centro"                       
##  [87] "cerro cristales"               "cerros de guadalupe"          
##  [89] "champagnat"                    "chapinero"                    
##  [91] "chiminangos"                   "Chiminangos"                  
##  [93] "chiminangos 1 etapa"           "chiminangos 2 etapa"          
##  [95] "chipichape"                    "ciudad 2000"                  
##  [97] "Ciudad 2000"                   "ciudad antejardin"            
##  [99] "ciudad bochalema"              "ciudad córdoba"               
## [101] "ciudad córdoba reservado"      "ciudad capri"                 
## [103] "ciudad cordoba"                "ciudad country"               
## [105] "ciudad del campo"              "ciudad jardín"                
## [107] "Ciudad Jardín"                 "ciudad jardin"                
## [109] "ciudad jardin pance"           "ciudad los álamos"            
## [111] "ciudad los alamos"             "ciudad meléndez"             
## [113] "ciudad melendez"               "ciudad modelo"                
## [115] "ciudad pacifica"               "Ciudad Pacifica"              
## [117] "ciudad real"                   "ciudad talanga"               
## [119] "ciudad universitaria"          "ciudadela comfandi"           
## [121] "ciudadela del río"             "ciudadela melendez"           
## [123] "ciudadela paso ancho"          "ciudadela pasoancho"          
## [125] "colinas de menga"              "colinas del bosque"           
## [127] "colinas del sur"               "colon"                        
## [129] "colseguros"                    "colseguros andes"             
## [131] "Colseguros Andes"              "comfenalco"                   
## [133] "compartir"                     "conjunto gibraltar"           
## [135] "cristóbal colón"               "cristales"                    
## [137] "cristobal colón"               "cuarto de legua"              
## [139] "departamental"                 "ed benjamin herrera"          
## [141] "el bosque"                     "El Bosque"                    
## [143] "el caney"                      "El Caney"                     
## [145] "el castillo"                   "el cedro"                     
## [147] "el diamante"                   "el dorado"                    
## [149] "el gran limonar"               "el guabal"                    
## [151] "el guabito"                    "el ingenio"                   
## [153] "El Ingenio"                    "el ingenio 3"                 
## [155] "el ingenio i"                  "el ingenio ii"                
## [157] "el ingenio iii"                "el jardín"                    
## [159] "el jordán"                     "el lido"                      
## [161] "el limonar"                    "el nacional"                  
## [163] "el paraíso"                    "el peñon"                     
## [165] "el prado"                      "el refugio"                   
## [167] "el rodeo"                      "el sena"                      
## [169] "el trébol"                    "el troncal"                   
## [171] "el vallado"                    "eucarístico"                  
## [173] "evaristo garcía"               "farrallones de pance"         
## [175] "fenalco kennedy"               "fepicol"                      
## [177] "flora"                         "flora industrial"             
## [179] "floralia"                      "fonaviemcali"                 
## [181] "francisco eladio ramirez"      "fuentes de la"                
## [183] "gaitan"                        "gran limonar"                 
## [185] "granada"                       "guadalupe"                    
## [187] "guadalupe alto"                "guaduales"                    
## [189] "guayaquil"                     "hacienda alferez real"        
## [191] "ingenio"                       "ingenio i"                    
## [193] "ingenio ii"                    "jamundi"                      
## [195] "jamundi alfaguara"             "jorge eliecer gaitán"         
## [197] "jorge isaacs"                  "jose manuel marroquín"        
## [199] "juanamb√∫"                     "juanambu"                     
## [201] "junín"                         "junin"                        
## [203] "la alborada"                   "la alianza"                   
## [205] "la arboleda"                   "la base"                      
## [207] "la buitrera"                   "la campiña"                   
## [209] "la cascada"                    "la ceibas"                    
## [211] "la esmeralda"                  "la flora"                     
## [213] "La Flora"                      "la floresta"                  
## [215] "la fortaleza"                  "la gran colombia"             
## [217] "la hacienda"                   "La Hacienda"                  
## [219] "la independencia"              "la libertad"                  
## [221] "la luisa"                      "la merced"                    
## [223] "la morada"                     "la nueva base"                
## [225] "la playa"                      "la portada al"                
## [227] "la primavera"                  "la reforma"                   
## [229] "la rivera"                     "la rivera i"                  
## [231] "la rivera ii"                  "la riverita"                  
## [233] "la riviera"                    "la selva"                     
## [235] "la villa del"                  "laflora"                      
## [237] "lares de comfenalco"           "las acacias"                  
## [239] "las américas"                 "las camelias"                 
## [241] "las ceibas"                    "las delicias"                 
## [243] "las granjas"                   "las quintas de"               
## [245] "las vegas"                     "las vegas de"                 
## [247] "libertadores"                  "los alamos"                   
## [249] "los alcázares"                 "los alcazares"                
## [251] "los andes"                     "los cámbulos"                 
## [253] "los cambulos"                  "los cristales"                
## [255] "los cristales club"            "los farallones"               
## [257] "los guaduales"                 "Los Guaduales"                
## [259] "los guayacanes"                "los jockeys"                  
## [261] "los libertadores"              "los parques barranquilla"     
## [263] "los robles"                    "lourdes"                      
## [265] "mamellan"                      "manzanares"                   
## [267] "mariano ramos"                 "marroquín iii"                
## [269] "mayapan las vegas"             "meléndez"                    
## [271] "melendez"                      "menga"                        
## [273] "metropolitano del norte"       "miradol del aguacatal"        
## [275] "miraflores"                    "Miraflores"                   
## [277] "morichal de comfandi"          "multicentro"                  
## [279] "municipal"                     "nápoles"                      
## [281] "napoles"                       "normandía"                    
## [283] "normandía west point"          "normandia"                    
## [285] "norte"                         "norte la flora"               
## [287] "nueva base"                    "nueva floresta"               
## [289] "nueva tequendama"              "oasis de comfandi"            
## [291] "oasis de pasoancho"            "occidente"                    
## [293] "pacará"                        "pacara"                       
## [295] "palmas del ingenio"            "pampa linda"                  
## [297] "pampalinda"                    "panamericano"                 
## [299] "pance"                         "Pance"                        
## [301] "parcelaciones pance"           "parque residencial el"        
## [303] "paseo de los"                  "paso del comercio"            
## [305] "pasoancho"                     "poblado campestre"            
## [307] "ponce"                         "popular"                      
## [309] "portada de comfandi"           "portales de comfandi"         
## [311] "porvenir"                      "prados de oriente"            
## [313] "prados del limonar"            "Prados Del Limonar"           
## [315] "prados del norte"              "Prados Del Norte"             
## [317] "prados del sur"                "primavera"                    
## [319] "primero de mayo"               "primitivo crespo"             
## [321] "puente del comercio"           "puente palma"                 
## [323] "quintas de don"                "Quintas De Don"               
## [325] "quintas de salomia"            "rafael uribe uribe"           
## [327] "refugio"                       "rep√∫blica de israel"         
## [329] "rincón de salomia"             "rincon de la"                 
## [331] "riveras del valle"             "rozo la torre"                
## [333] "saavedra galindo"              "salomia"                      
## [335] "samanes"                       "samanes de guadalupe"         
## [337] "sameco"                        "san antonio"                  
## [339] "san bosco"                     "san carlos"                   
## [341] "san cayetano"                  "san fernando"                 
## [343] "San Fernando"                  "san fernando nuevo"           
## [345] "san fernando viejo"            "san joaquín"                  
## [347] "san joaquin"                   "san juan bosco"               
## [349] "san judas"                     "san judas tadeo"              
## [351] "san luís"                      "san luis"                     
## [353] "san nicolás"                   "san nicolas"                  
## [355] "san pedro"                     "san vicente"                  
## [357] "santa"                         "santa anita"                  
## [359] "Santa Anita"                   "santa anita sur"              
## [361] "santa bárbara"                 "santa elena"                  
## [363] "santa fe"                      "santa helena de"              
## [365] "santa isabel"                  "Santa Isabel"                 
## [367] "santa mónica"                  "santa mónica alta"            
## [369] "santa mónica popular"          "santa mónica residencial"     
## [371] "santa monica"                  "Santa Monica"                 
## [373] "santa monica norte"            "santa monica popular"         
## [375] "santa monica residencial"      "santa rita"                   
## [377] "santa rosa"                    "santa teresita"               
## [379] "Santa Teresita"                "Santafe"                      
## [381] "santander"                     "santo domingo"                
## [383] "Santo Domingo"                 "sector aguacatal"             
## [385] "sector cañaveralejo guadalupe" "seminario"                    
## [387] "sierras de normandía"          "siete de agosto"              
## [389] "simón bolivar"                 "tejares cristales"            
## [391] "tejares de san"                "templete"                     
## [393] "tequendama"                    "tequendema"                   
## [395] "terrón colorado"               "torres de comfandi"           
## [397] "unión de vivienda"             "unicentro cali"               
## [399] "urbanización barranquilla"     "urbanización boyacá"          
## [401] "urbanización colseguros"       "urbanización la flora"        
## [403] "urbanización la merced"        "urbanización la nueva"        
## [405] "urbanización las cascadas"     "urbanización nueva granada"   
## [407] "urbanización pacara"           "urbanización río lili"        
## [409] "urbanización san joaquin"      "urbanización tequendama"      
## [411] "urbanizacion el saman"         "urbanizacion gratamira"       
## [413] "urbanizacion lili"             "valle de lili"                
## [415] "valle del lili"                "Valle Del Lili"               
## [417] "valle grande"                  "versalles"                    
## [419] "villa colombia"                "villa de veracruz"            
## [421] "villa del lago"                "villa del parque"             
## [423] "villa del prado"               "Villa Del Prado"              
## [425] "villa del sol"                 "villa del sur"                
## [427] "Villas De Veracruz"            "villas de veracruz"           
## [429] "vipasa"                        "zona centro"                  
## [431] "zona norte"                    "zona norte los"               
## [433] "zona oeste"                    "zona oriente"                 
## [435] "zona residencial"              "zona sur"                     
## [437] NA

A continuación, se presenta los valores ausentes en el conjunto de datos

valores_faltantes <- colSums(is.na(df))
cat("Valores faltantes por columna:\n")
## Valores faltantes por columna:
cat(paste(names(valores_faltantes), ": ", valores_faltantes, sep = ""), sep = "\n")
## id: 3
## zona: 3
## piso: 2638
## estrato: 3
## preciom: 2
## areaconst: 3
## parqueaderos: 1605
## banios: 3
## habitaciones: 3
## tipo: 3
## barrio: 3
## longitud: 3
## latitud: 3
#Graficando la cantidad de valores ausentes por atributo
barplot(
  valores_faltantes,
  names.arg = names(valores_faltantes),
  col = "skyblue",
  main = "Valores Faltantes por Atributos",
  ylim = c(0, max(valores_faltantes) + 500),
  las = 2,
  cex.names = 0.7
)

El gráfico revela claramente que los atributos “piso” y “parqueaderos” presentan una notable cantidad de datos faltantes, destacándose como las variables con mayor ausencia de información. Por otro lado, los demás atributos muestran una proporción significativamente menor de valores faltantes.

Generando el diagrama de caja y bigotes para todos los atributos numéricos

columnas_numericas <- df[sapply(df, is.numeric)]

# Crear el boxplot
# Configurar el tamaño de las etiquetas
par(cex.axis = 0.7)

boxplot(
  columnas_numericas, 
  main = "Boxplot Atributos Numéricos", 
  las = 2
)

Se muestra un resumen estadístico de los datos

resumen_estadistico <- summary(df)
print(resumen_estadistico)
##        id           zona               piso              estrato     
##  Min.   :   1   Length:8322        Length:8322        Min.   :3.000  
##  1st Qu.:2080   Class :character   Class :character   1st Qu.:4.000  
##  Median :4160   Mode  :character   Mode  :character   Median :5.000  
##  Mean   :4160                                         Mean   :4.634  
##  3rd Qu.:6240                                         3rd Qu.:5.000  
##  Max.   :8319                                         Max.   :6.000  
##  NA's   :3                                            NA's   :3      
##     preciom         areaconst       parqueaderos        banios      
##  Min.   :  58.0   Min.   :  30.0   Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 220.0   1st Qu.:  80.0   1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 330.0   Median : 123.0   Median : 2.000   Median : 3.000  
##  Mean   : 433.9   Mean   : 174.9   Mean   : 1.835   Mean   : 3.111  
##  3rd Qu.: 540.0   3rd Qu.: 229.0   3rd Qu.: 2.000   3rd Qu.: 4.000  
##  Max.   :1999.0   Max.   :1745.0   Max.   :10.000   Max.   :10.000  
##  NA's   :2        NA's   :3        NA's   :1605     NA's   :3       
##   habitaciones        tipo              barrio             longitud     
##  Min.   : 0.000   Length:8322        Length:8322        Min.   :-76.59  
##  1st Qu.: 3.000   Class :character   Class :character   1st Qu.:-76.54  
##  Median : 3.000   Mode  :character   Mode  :character   Median :-76.53  
##  Mean   : 3.605                                         Mean   :-76.53  
##  3rd Qu.: 4.000                                         3rd Qu.:-76.52  
##  Max.   :10.000                                         Max.   :-76.46  
##  NA's   :3                                              NA's   :3       
##     latitud     
##  Min.   :3.333  
##  1st Qu.:3.381  
##  Median :3.416  
##  Mean   :3.418  
##  3rd Qu.:3.452  
##  Max.   :3.498  
##  NA's   :3

nota: En esta fase, la matriz de correlación no se exhibe debido a la presencia de valores faltantes en todos los atributos. Al calcular la matriz de correlación de esta manera, se generan valores NA en las celdas fuera de la diagonal principal.

Preprocesamiento de los datos

Dado que la columna de identificación (id) no aporta información relevante para el análisis, se optará por su eliminación, junto con la variable “barrio”.

df_pre <- df

# Eliminar la columna "id" del dataframe
df_pre <- df_pre[, !(names(df_pre) == "id")]
# Eliminar la columna "barrio" del dataframe modificado vivienda_pre
df_pre <- df_pre[, !(names(df_pre) == "barrio")]
head(df_pre, 5)
##           zona piso estrato preciom areaconst parqueaderos banios habitaciones
## 1 Zona Oriente <NA>       3     250        70            1      3            6
## 2 Zona Oriente <NA>       3     320       120            1      2            3
## 3 Zona Oriente <NA>       3     350       220            2      2            4
## 4     Zona Sur   02       4     400       280            3      5            3
## 5   Zona Norte   01       5     260        90            1      2            3
##          tipo  longitud latitud
## 1        Casa -76.51168 3.43382
## 2        Casa -76.51237 3.43369
## 3        Casa -76.51537 3.43566
## 4        Casa -76.54000 3.43500
## 5 Apartamento -76.51350 3.45891

Debido a la alta presencia de valores faltantes en el atributo “parqueadero”, se procederá a su imputación mediante la sustitución de los valores ausentes por la mediana.

mediana_par <- median(df_pre$parqueaderos, na.rm = TRUE)

df_pre$parqueaderos <- ifelse(
  is.na(df_pre$parqueaderos), 
  mediana_par, df_pre$parqueaderos
)

#Contanto los valores vacíos del atributo parqueadero
cat("Cantidad valores vacíos atributo parqueadero: ", sum(is.na(df_pre$parqueaderos)), "\n")
## Cantidad valores vacíos atributo parqueadero:  0

La columna “piso” se registra como tipo “chr” (caracter), sin embargo, su contenido sugiere una naturaleza numérica, como se evidencia en los valores únicos presentes. Por lo tanto, se procederá a procesar la columna de la siguiente manera:

  1. Se realizará la conversión de los valores de la columna “piso” a tipo numérico.
  2. Se llevará a cabo la imputación de los valores faltantes utilizando la mediana como referencia.
#1. Se realizará la conversión de los valores de la columna "piso" a tipo numérico.
df_pre$piso <- as.numeric(df_pre$piso)
str(df_pre)
## 'data.frame':    8322 obs. of  11 variables:
##  $ zona        : chr  "Zona Oriente" "Zona Oriente" "Zona Oriente" "Zona Sur" ...
##  $ piso        : num  NA NA NA 2 1 1 1 1 2 2 ...
##  $ estrato     : num  3 3 3 4 5 5 4 5 5 5 ...
##  $ preciom     : num  250 320 350 400 260 240 220 310 320 780 ...
##  $ areaconst   : num  70 120 220 280 90 87 52 137 150 380 ...
##  $ parqueaderos: num  1 1 2 3 1 1 2 2 2 2 ...
##  $ banios      : num  3 2 2 5 2 3 2 3 4 3 ...
##  $ habitaciones: num  6 3 4 3 3 3 3 4 6 3 ...
##  $ tipo        : chr  "Casa" "Casa" "Casa" "Casa" ...
##  $ longitud    : num  -76.5 -76.5 -76.5 -76.5 -76.5 ...
##  $ latitud     : num  3.43 3.43 3.44 3.44 3.46 ...
#2. Se llevará a cabo la imputación de los valores faltantes utilizando la mediana como referencia.
mediana_pisos <- median(df_pre$piso, na.rm = TRUE)
df_pre$piso[is.na(df_pre$piso)] <- mediana_pisos
valores_ausentes_piso <- sum(is.na(df_pre$piso))
print(paste("La cantidad de valores ausentes en la columna 'piso' es:", valores_ausentes_piso))
## [1] "La cantidad de valores ausentes en la columna 'piso' es: 0"
valores_faltantes <- colSums(is.na(df_pre))
cat("Valores faltantes por columna:\n")
## Valores faltantes por columna:
cat(paste(names(valores_faltantes), ": ", valores_faltantes, sep = ""), sep = "\n")
## zona: 3
## piso: 0
## estrato: 3
## preciom: 2
## areaconst: 3
## parqueaderos: 0
## banios: 3
## habitaciones: 3
## tipo: 3
## longitud: 3
## latitud: 3

Dado que la proporción de valores faltantes es insignificante en comparación con la cantidad total de registros en el dataframe, se opta por eliminar dichos valores faltantes.

df_pre <- na.omit(df_pre)

valores_faltantes <- colSums(is.na(df_pre))
cat("Valores faltantes por columna:\n")
## Valores faltantes por columna:
cat(paste(names(valores_faltantes), ": ", valores_faltantes, sep = ""), sep = "\n")
## zona: 0
## piso: 0
## estrato: 0
## preciom: 0
## areaconst: 0
## parqueaderos: 0
## banios: 0
## habitaciones: 0
## tipo: 0
## longitud: 0
## latitud: 0

Previamente a la aplicación de cualquier análisis, es esencial llevar a cabo la codificación de las variables categóricas presentes en el conjunto de datos. Se empleará la codificación one-hot para las variables “zona” y “tipo”.

Codificación de la variable “zona”

library(caret)
## Loading required package: lattice
## 
## Attaching package: 'lattice'
## The following object is masked from 'package:boot':
## 
##     melanoma
dummy_spec <- dummyVars(~ zona, data = df_pre, fullRank = FALSE)
zona_dummy <- predict(dummy_spec, newdata = df_pre)
df_pre <- cbind(df_pre, zona_dummy)
df_pre$zona <- NULL

#Para reducir la redundancia en los datos, se procede a eliminar la columna "zonaZona Sur". 
df_pre <- df_pre[, colnames(df_pre) != "zonaZona Sur"]

#Cambiando el nombre de las columnas
indice_columna <- which(colnames(df_pre) == "zonaZona Centro")
colnames(df_pre)[indice_columna] <- "Centro"

indice_columna <- which(colnames(df_pre) == "zonaZona Norte")
colnames(df_pre)[indice_columna] <- "Norte"

indice_columna <- which(colnames(df_pre) == "zonaZona Oeste")
colnames(df_pre)[indice_columna] <- "Oeste"

indice_columna <- which(colnames(df_pre) == "zonaZona Oriente")
colnames(df_pre)[indice_columna] <- "Oriente"


head(df_pre, 5)
##   piso estrato preciom areaconst parqueaderos banios habitaciones        tipo
## 1    3       3     250        70            1      3            6        Casa
## 2    3       3     320       120            1      2            3        Casa
## 3    3       3     350       220            2      2            4        Casa
## 4    2       4     400       280            3      5            3        Casa
## 5    1       5     260        90            1      2            3 Apartamento
##    longitud latitud Centro Norte Oeste Oriente
## 1 -76.51168 3.43382      0     0     0       1
## 2 -76.51237 3.43369      0     0     0       1
## 3 -76.51537 3.43566      0     0     0       1
## 4 -76.54000 3.43500      0     0     0       0
## 5 -76.51350 3.45891      0     1     0       0

Codificación de la variable “tipo”

library(caret)

dummy_spec <- dummyVars(~ tipo, data = df_pre, fullRank = FALSE)
zona_dummy <- predict(dummy_spec, newdata = df_pre)
df_pre <- cbind(df_pre, zona_dummy)
df_pre$tipo <- NULL

#Para reducir la redundancia en los datos, se procede a eliminar la columna "tipoApartamento".
df_pre <- df_pre[, colnames(df_pre) != "tipoApartamento"]


head(df_pre, 5)
##   piso estrato preciom areaconst parqueaderos banios habitaciones  longitud
## 1    3       3     250        70            1      3            6 -76.51168
## 2    3       3     320       120            1      2            3 -76.51237
## 3    3       3     350       220            2      2            4 -76.51537
## 4    2       4     400       280            3      5            3 -76.54000
## 5    1       5     260        90            1      2            3 -76.51350
##   latitud Centro Norte Oeste Oriente tipoCasa
## 1 3.43382      0     0     0       1        1
## 2 3.43369      0     0     0       1        1
## 3 3.43566      0     0     0       1        1
## 4 3.43500      0     0     0       0        1
## 5 3.45891      0     1     0       0        0

Pasos requeridos para la obtención de los resultados

Casas

Actividad 1

Realice un filtro a la base de datos e incluya solo las ofertas de : base1: casas, de la zona norte de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).

#Filtrando la base de datos para para incluir solo las casas de la zona norte
casas_zona_norte <- subset(df_pre, tipoCasa == 1 & Norte == 1)
head(casas_zona_norte, 3)
##    piso estrato preciom areaconst parqueaderos banios habitaciones  longitud
## 9     2       5     320       150            2      4            6 -76.51341
## 10    2       5     780       380            2      3            3 -76.51674
## 11    2       6     750       445            2      7            6 -76.52950
##    latitud Centro Norte Oeste Oriente tipoCasa
## 9  3.47968      0     1     0       0        1
## 10 3.48721      0     1     0       0        1
## 11 3.38527      0     1     0       0        1
tabla_tipos_propiedad <- table(casas_zona_norte$tipoCasa)
print("Tabla de frecuencia de tipos de propiedad (solo zona norte):")
## [1] "Tabla de frecuencia de tipos de propiedad (solo zona norte):"
print(tabla_tipos_propiedad)
## 
##   1 
## 722

El resultado anterior indica que hay 722 registros catalogados como tipo de propiedad “casa”, ya que están representados por el valor 1 en la variable correspondiente.

# Tabla de frecuencia de zonas (solo debería haber registros en la zona norte)
tabla_zonas <- data.frame(
  Zona = c("Norte", "Centro", "Oeste", "Oriente"),
  Cantidad = c(sum(casas_zona_norte$Norte), sum(casas_zona_norte$Centro), sum(casas_zona_norte$Oeste), sum(casas_zona_norte$Oriente))
)
print(tabla_zonas)
##      Zona Cantidad
## 1   Norte      722
## 2  Centro        0
## 3   Oeste        0
## 4 Oriente        0
# Tabla de resumen de variables numéricas para las casas de la zona norte
resumen_casas_zona_norte <- data.frame(
  Precio_Medio = mean(casas_zona_norte$preciom),
  Area_Construida_Promedio = mean(casas_zona_norte$areaconst),
  Num_Habitaciones_Promedio = mean(casas_zona_norte$habitaciones),
  Num_Baños_Promedio = mean(casas_zona_norte$banios),
  Num_Parqueaderos_Promedio = mean(casas_zona_norte$parqueaderos)
)
print(resumen_casas_zona_norte)
##   Precio_Medio Area_Construida_Promedio Num_Habitaciones_Promedio
## 1     445.9058                 264.8505                  4.506925
##   Num_Baños_Promedio Num_Parqueaderos_Promedio
## 1           3.555402                  2.109418

A continuación, se presenta el mapa con los registros filtrados:

library(leaflet)

mapa1 <- leaflet() %>%
  addTiles()

mapa1%>%
  addMarkers(
    data = casas_zona_norte, 
    lng = ~longitud, 
    lat = ~latitud,
)

Para discutir los puntos ubicados en zonas no correspondientes en el mapa, se necesita tener información adicional sobre cómo se geocodificaron los datos. Si los puntos que no están en la zona norte se han incluido por error, podría ser necesario revisar y corregir el proceso de geocodificación o los criterios de inclusión en la zona norte.

Actividad 2

Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de la casa) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.

A continuación se cálcula la matriz de correlación

library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
matriz_correlacion <- cor(casas_zona_norte[
  c(
    "preciom", 
    "areaconst", 
    "estrato", 
    "banios", 
    "habitaciones",
    "parqueaderos")
])

# Visualizar la matriz de correlación con plotly
plot_ly(z = matriz_correlacion, colorscale = "Viridis", type = "heatmap", 
        x = colnames(matriz_correlacion), y = colnames(matriz_correlacion)) %>%
  layout(title = "Matriz de Correlación")

Al analizar la matriz de correlación, se destaca que las variables que presentan las correlaciones más altas con el precio son áreaconst, estrato y baños, con coeficientes de correlación de 0.69, 0.60 y 0.67, respectivamente. A continuación, se procede a explorar las relaciones entre cada una de estas variables y el precio mediante gráficos de dispersión.

# Gráfico de dispersión de precio vs. área construida
scatter_plot <- plot_ly(casas_zona_norte, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Área Construida: ", areaconst, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Área Construida",
         xaxis = list(title = "Área Construida"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot
# Gráfico de dispersión de precio vs. estrato
scatter_plot <- plot_ly(casas_zona_norte, x = ~estrato, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Estrato: ", estrato, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Estrato",
         xaxis = list(title = "Estrato"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot
# Gráfico de dispersión de precio vs. baños
scatter_plot <- plot_ly(casas_zona_norte, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Baños: ", banios, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Baños",
         xaxis = list(title = "Baños"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot

Actividad 3

Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).

#Estimación del modelo de regresión lineal multiple
modelo <- lm(preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, data = casas_zona_norte )

#Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = casas_zona_norte)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -924.94  -77.71  -17.66   45.90 1081.29 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -251.05177   30.11848  -8.335 3.94e-16 ***
## areaconst       0.81090    0.04352  18.634  < 2e-16 ***
## estrato        84.61108    7.17727  11.789  < 2e-16 ***
## habitaciones    0.95948    4.10569   0.234  0.81529    
## parqueaderos   16.55976    5.70396   2.903  0.00381 ** 
## banios         24.57669    5.35583   4.589 5.26e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 158.2 on 716 degrees of freedom
## Multiple R-squared:  0.6548, Adjusted R-squared:  0.6524 
## F-statistic: 271.6 on 5 and 716 DF,  p-value: < 2.2e-16

Análisis de los coeficientes

Intercept: Representa el precio promedio estimado de una casa cuando todas las variables independientes son iguales a cero (lo cual no tendría sentido en la realidad). Su valor negativo indica una tendencia general a precios negativos en ese caso hipotético.

areaconst: Un coeficiente positivo y altamente significativo (p-valor < 2e-16) indica que a mayor área construida, mayor es el precio estimado de la casa.

estrato: Un coeficiente positivo y altamente significativo (p-valor < 2e-16) indica que a mayor estrato socioeconómico del sector, mayor es el precio estimado de la casa.

habitaciones: Un coeficiente positivo pero no significativo (p-valor = 0.81529) indica que el número de habitaciones no tiene un impacto estadísticamente significativo en el precio estimado de la casa según este modelo.

parqueaderos: Un coeficiente positivo y significativo (p-valor = 0.00381) indica que a mayor número de parqueaderos, mayor es el precio estimado de la casa.

banios: Un coeficiente positivo y altamente significativo (p-valor = 5.26e-06) indica que a mayor número de baños, mayor es el precio estimado de la casa.

Análisis del R2

Un valor de R-cuadrado ajustado de 0.6524 indica que el modelo explica aproximadamente el 65% de la varianza del precio de la vivienda en esta muestra.

Para mejorar la precisión y el rendimiento del modelo, se pueden implementar las siguientes estrategias:

Utilizar la regresión LASSO y la regresión RIDGE: Estas técnicas penalizan los coeficientes de las variables, lo que ayuda a evitar el sobreajuste y conduce a un modelo más robusto y generalizable.

Identificar y eliminar o transformar valores atípicos: Es crucial identificar y eliminar o transformar valores atípicos, ya que estos pueden distorsionar los resultados del modelo y afectar negativamente su precisión.

Actividad 4

Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

Gráfico Q-Q:

residuos <- resid(modelo)
qqnorm(residuos)
qqline(residuos)

En el análisis de los resultados, se observa que los puntos se encuentran mayoritariamente a lo largo de una línea diagonal recta, con algunas desviaciones en cada una de las colas de la distribución.

hist(residuos)

La imagen muestra que los residuos se encuentran cerca de cero, lo que indica que el modelo es preciso en la mayoría de las predicciones. Hay algunos residuos que se encuentran lejos de cero, lo que indica que el modelo no es perfecto y hay algunas predicciones que son menos precisas. Al observar la imagen, se puede decir que el histograma podría mostrar un comportamiento normal.

Prueba de Kolmogorov-Smirnov

ks.test(residuos, "pnorm")
## 
##  Asymptotic one-sample Kolmogorov-Smirnov test
## 
## data:  residuos
## D = 0.57201, p-value < 2.2e-16
## alternative hypothesis: two-sided

Dado que el valor p es menor que cualquier nivel de significancia comúnmente utilizado (por ejemplo, 0.05), podemos rechazar la hipótesis nula de que los datos siguen la distribución teórica especificada. En otras palabras, hay evidencia suficiente para concluir que los residuos no siguen una distribución normal.

Gráfico de dispersión de residuos estandarizados

# Crear el modelo de regresión (reemplaza 'modelo' con el nombre de tu modelo)
residuos <- resid(modelo)
valores_ajustados <- predict(modelo)

# Calcula los residuos estandarizados
residuos_estandarizados <- residuos / sd(residuos)

# Gráfico de dispersión de residuos estandarizados vs valores ajustados
plot(valores_ajustados, residuos_estandarizados, xlab = "Valores ajustados", ylab = "Residuos estandarizados", main = "Dispersión de Residuos Estándarizados vs Valores Ajustados")
abline(h = 0, col = "red")  # Agrega una línea horizontal en y = 0

El gráfico de dispersión de residuos estandarizados versus valores ajustados nos permite evaluar algunos aspectos importantes del modelo de regresión:

Normalidad: En general, los residuos deberían seguir una distribución normal alrededor de la línea horizontal en el centro del gráfico (residuo = 0). En este caso, se observa una ligera curvatura en la parte superior del gráfico, lo que podría indicar una leve desviación de la normalidad.

Homocedasticidad: La dispersión de los residuos debería ser constante a lo largo de los valores ajustados. Sin embargo, se observa un aumento en la dispersión para valores ajustados más altos, lo que sugiere heterocedasticidad.

Linealidad: La forma general de la nube de puntos parece seguir una tendencia lineal, aunque con algunas desviaciones.

Precisión: La mayoría de los puntos se encuentran relativamente cerca de la línea horizontal (residuo = 0), lo que indica un ajuste razonable del modelo a los datos.

Recomendaciones: Se podría explorar la posibilidad de utilizar un modelo de regresión no lineal para mejorar el ajuste a los datos.

Prueba de Breusch-Pagan o prueba de White

library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
# Prueba de Breusch-Pagan
bptest(modelo)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo
## BP = 132.24, df = 5, p-value < 2.2e-16
# Prueba de White
bptest(modelo, studentize = FALSE)
## 
##  Breusch-Pagan test
## 
## data:  modelo
## BP = 812.34, df = 5, p-value < 2.2e-16

Tanto la prueba BP como la prueba W presentan valores de p menores a 2.2e-16, lo que permite rechazar la hipótesis nula de homocedasticidad. Esto significa que la varianza de los errores no es constante en todas las observaciones, lo que se conoce como heterocedasticidad.

Recomendaciones para corregir la heterocedasticidad

Utilizar un modelo de regresión con ponderaciones: Asignar pesos a las observaciones para compensar la heterocedasticidad. Por ejemplo, se pueden utilizar ponderaciones por la varianza de los errores.

Transformar las variables: Transformar las variables para que la varianza de los errores sea más constante. Algunas transformaciones comunes son la transformación logarítmica o la raíz cuadrada.

Utilizar estimadores robustos: Estimar los coeficientes del modelo utilizando métodos que son menos sensibles a la heterocedasticidad. Algunos ejemplos de estimadores robustos son el estimador de mínimos cuadrados ponderados o el estimador M.

Prueba de Ausencia de multicolinealidad

library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:boot':
## 
##     logit
# Calcular el VIF para cada variable independiente en el modelo
vif <- vif(modelo)
vif
##    areaconst      estrato habitaciones parqueaderos       banios 
##     1.523989     1.433058     1.621630     1.120670     1.918323

Todas las variables tienen valores de VIF menores a 10, lo que indica que no hay un problema de colinealidad entre las variables del modelo.

Actividad 5

Con el modelo identificado debe predecir el precio de la vivienda con las características de la primera solicitud.

vivienda_nueva_4 <- data.frame(
  areaconst = 200,
  estrato = 4,
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)

vivienda_nueva_5 <- data.frame(
  areaconst = 200,
  estrato = 5,
  habitaciones = 4,
  parqueaderos = 1,
  banios = 2
)

prediccion_4 <- predict(modelo, newdata = vivienda_nueva_4)
prediccion_5 <- predict(modelo, newdata = vivienda_nueva_5)

resultado_4 <- sprintf(
  "El precio predicho para la vivienda estrato 4: %.0f", 
  prediccion_4
)

resultado_5 <- sprintf(
  "El precio predicho para la vivienda estrato 5: %.0f", 
  prediccion_5
)

print(resultado_4)
## [1] "El precio predicho para la vivienda estrato 4: 319"
print(resultado_5)
## [1] "El precio predicho para la vivienda estrato 5: 404"

Se utiliza el modelo para predecir el valor de una casa con las características definidas, considerando los estratos 4 y 5 por separado.

Actividad 6

Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 1. Tenga encuenta que la empresa tiene crédito pre-aprobado de máximo 350 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.

Se emplea el precio obtenido de la predicción del modelo para una casa de estrato 4, ya que la predicción para una casa de estrato 5 supera el límite del crédito pre-aprobado. Utilizamos el precio de la casa de estrato 4 junto con las demás características, asegurándonos de que no exceda el monto máximo. Además, se realiza una búsqueda en ambos estratos para verificar si existen otras ofertas disponibles.

ofertas_casas <- subset(
  casas_zona_norte,
  preciom <= 350 &
  preciom >= 319 &
  areaconst >= 200 &
  parqueaderos >= 1 &
  banios >= 2 &
  habitaciones >= 4 &
  estrato %in% c(4,5)
)

ofertas_casas <- subset(
  ofertas_casas[order(ofertas_casas$preciom), ]
)

ofertas_casas <- head(ofertas_casas, 5)

ofertas_casas
##      piso estrato preciom areaconst parqueaderos banios habitaciones  longitud
## 3491    2       5     320       200            2      4            4 -76.51524
## 3512    2       5     320       230            2      4            4 -76.52353
## 4020    3       4     320       200            2      4            4 -76.51156
## 6907    3       5     320       210            2      3            5 -76.51200
## 4016    3       5     321       249            1      5            5 -76.50291
##      latitud Centro Norte Oeste Oriente tipoCasa
## 3491 3.48893      0     1     0       0        1
## 3512 3.48352      0     1     0       0        1
## 4020 3.48029      0     1     0       0        1
## 6907 3.47600      0     1     0       0        1
## 4016 3.46757      0     1     0       0        1

A continuación, se presenta el mapa con los registros filtrados:

library(leaflet)

mapa <- leaflet() %>%
  addTiles()

mapa%>%
  addMarkers(
    data = ofertas_casas, 
    lng = ~longitud, 
    lat = ~latitud,
    popup = paste("Precio:", ofertas_casas$preciom, "$", 
                           "<br>Habitaciones:", ofertas_casas$habitaciones,
                           "<br>Baños:", ofertas_casas$banios)
)

Apartamentos

Actividad 1

Realice un filtro a la base de datos e incluya solo las ofertas de : base2: apartamentos, de la zona sur de la ciudad. Presente los primeros 3 registros de las bases y algunas tablas que comprueben la consulta. (Adicional un mapa con los puntos de las bases. Discutir si todos los puntos se ubican en la zona correspondiente o se presentan valores en otras zonas, por que?).

#Filtrando la base de datos para para incluir solo los apartamentos de la zona sur
apartamentos_sur <- subset(
  df_pre, 
  tipoCasa == 0 & 
    Centro == 0 & 
    Norte == 0 &
    Oeste == 0 &
    Oriente == 0
)
head(apartamentos_sur, 3)
##     piso estrato preciom areaconst parqueaderos banios habitaciones  longitud
## 24     5       4     290        96            1      2            3 -76.53464
## 164    2       3      78        40            1      1            2 -76.50100
## 264    3       6     875       194            2      5            3 -76.55700
##     latitud Centro Norte Oeste Oriente tipoCasa
## 24  3.44987      0     0     0       0        0
## 164 3.40000      0     0     0       0        0
## 264 3.45900      0     0     0       0        0
tabla_tipos_propiedad <- table(apartamentos_sur$tipoCasa)
print("Tabla de frecuencia de tipos de propiedad (solo zona sur):")
## [1] "Tabla de frecuencia de tipos de propiedad (solo zona sur):"
print(tabla_tipos_propiedad)
## 
##    0 
## 2787

El resultado anterior indica que hay 2787 registros catalogados como tipo de propiedad “apartamento”, ya que están representados por el valor 0 en la variable correspondiente.

# Tabla de frecuencia de zonas (solo debería haber registros en la zona norte)
tabla_zonas <- data.frame(
  Zona = c("Norte", "Centro", "Oeste", "Oriente"),
  Cantidad = c(sum(apartamentos_sur$Norte), sum(apartamentos_sur$Centro), sum(apartamentos_sur$Oeste), sum(apartamentos_sur$Oriente))
)
print(tabla_zonas)
##      Zona Cantidad
## 1   Norte        0
## 2  Centro        0
## 3   Oeste        0
## 4 Oriente        0
# Tabla de resumen de variables numéricas para los apartamentos de la zona sur
resumen_apartamentos_sur <- data.frame(
  Precio_Medio = mean(apartamentos_sur$preciom),
  Area_Construida_Promedio = mean(apartamentos_sur$areaconst),
  Num_Habitaciones_Promedio = mean(apartamentos_sur$habitaciones),
  Num_Baños_Promedio = mean(apartamentos_sur$banios),
  Num_Parqueaderos_Promedio = mean(apartamentos_sur$parqueaderos)
)
print(resumen_apartamentos_sur)
##   Precio_Medio Area_Construida_Promedio Num_Habitaciones_Promedio
## 1     297.2917                 97.47028                  2.965554
##   Num_Baños_Promedio Num_Parqueaderos_Promedio
## 1           2.488339                  1.499821

A continuación, se presenta el mapa con los registros filtrados:

library(leaflet)

mapa1 <- leaflet() %>%
  addTiles()

mapa1%>%
  addMarkers(
    data = apartamentos_sur, 
    lng = ~longitud, 
    lat = ~latitud,
)

Para discutir los puntos ubicados en zonas no correspondientes en el mapa, se necesita tener información adicional sobre cómo se geocodificaron los datos. Si los puntos que no están en la zona sur se han incluido por error, podría ser necesario revisar y corregir el proceso de geocodificación o los criterios de inclusión en la zona sur.

Actividad 2

Realice un análisis exploratorio de datos enfocado en la correlación entre la variable respuesta (precio de un apartamento) en función del área construida, estrato, numero de baños, numero de habitaciones y zona donde se ubica la vivienda. Use gráficos interactivos con el paquete plotly e interprete los resultados.

A continuación se cálcula la matriz de correlación

library(plotly)

matriz_correlacion <- cor(apartamentos_sur[
  c(
    "preciom", 
    "areaconst", 
    "estrato", 
    "banios", 
    "habitaciones",
    "parqueaderos")
])

# Visualizar la matriz de correlación con plotly
plot_ly(z = matriz_correlacion, colorscale = "Viridis", type = "heatmap", 
        x = colnames(matriz_correlacion), y = colnames(matriz_correlacion)) %>%
  layout(title = "Matriz de Correlación")

Al analizar la matriz de correlación, se destaca que las variables que presentan las correlaciones más altas con el precio son áreaconst, estrato y baños, con coeficientes de correlación de 0.76, 0.62 y 0.72, respectivamente. A continuación, se procede a explorar las relaciones entre cada una de estas variables y el precio mediante gráficos de dispersión.

# Gráfico de dispersión de precio vs. área construida
scatter_plot <- plot_ly(apartamentos_sur, x = ~areaconst, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Área Construida: ", areaconst, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Área Construida",
         xaxis = list(title = "Área Construida"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot
# Gráfico de dispersión de precio vs. estrato
scatter_plot <- plot_ly(apartamentos_sur, x = ~estrato, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Estrato: ", estrato, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Estrato",
         xaxis = list(title = "Estrato"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot
# Gráfico de dispersión de precio vs. baños
scatter_plot <- plot_ly(apartamentos_sur, x = ~banios, y = ~preciom, type = 'scatter', mode = 'markers',
                        text = ~paste("Baños: ", banios, "<br>Precio: ", preciom)) %>%
  layout(title = "Precio vs. Baños",
         xaxis = list(title = "Baños"),
         yaxis = list(title = "Precio"))

# Mostrar el gráfico
scatter_plot

Actividad 3

Estime un modelo de regresión lineal múltiple con las variables del punto anterior (precio = f(área construida, estrato, número de cuartos, número de parqueaderos, número de baños ) ) e interprete los coeficientes si son estadísticamente significativos. Las interpretaciones deber están contextualizadas y discutir si los resultados son lógicos. Adicionalmente interprete el coeficiente R2 y discuta el ajuste del modelo e implicaciones (que podrían hacer para mejorarlo).

#Estimación del modelo de regresión lineal multiple
modelo2 <- lm(
  preciom ~ areaconst + estrato + habitaciones + parqueaderos + banios, 
  data = apartamentos_sur 
)

#Resumen del modelo
summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = apartamentos_sur)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1233.80   -45.98    -2.05    42.25   927.76 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -314.61850   13.51614 -23.277  < 2e-16 ***
## areaconst       1.45139    0.04876  29.766  < 2e-16 ***
## estrato        68.93151    2.66560  25.860  < 2e-16 ***
## habitaciones  -16.28835    3.41634  -4.768 1.96e-06 ***
## parqueaderos   51.59374    3.16010  16.327  < 2e-16 ***
## banios         49.11206    3.02770  16.221  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 95.01 on 2781 degrees of freedom
## Multiple R-squared:  0.7544, Adjusted R-squared:  0.754 
## F-statistic:  1709 on 5 and 2781 DF,  p-value: < 2.2e-16

Análisis de los coeficientes

Intercepto: El intercepto del modelo, que es de -$314.618, representa el precio promedio estimado de un apartamento cuando todas las demás variables del modelo son iguales a cero. Es importante tener en cuenta que esta situación no se presenta en la realidad, ya que es imposible que un apartamento tenga un área construida, estrato, número de habitaciones, parqueaderos y baños iguales a cero.

Área construida: Por cada metro cuadrado adicional de área construida, el precio del apartamento aumenta en $1.45. El resultado es lógico, ya que un apartamento más grande generalmente tiene un precio más alto.

Estrato: El precio del apartamento aumenta en $68.93 por cada estrato adicional. Los apartamentos en estratos más altos generalmente tienen mejores servicios y ubicación, lo que justifica el mayor precio.

Habitaciones: El precio del apartamento disminuye en $16.29 por cada habitación adicional. Es posible que los apartamentos con más habitaciones tengan un precio por metro cuadrado menor, ya que el espacio adicional se distribuye en más habitaciones.

Parqueaderos: El precio del apartamento aumenta en $51.59 por cada parqueadero adicional. La disponibilidad de parqueaderos es un factor importante en la decisión de compra de un apartamento, lo que explica el aumento en el precio.

Baños: El precio del apartamento aumenta en $49.11 por cada baño adicional. Los baños son un elemento importante en la comodidad de un apartamento, lo que justifica el aumento en el precio.

Todos los coeficientes de regresión son estadísticamente significativos con un nivel de significancia menor a 0.05. Esto significa que hay una probabilidad muy baja de que los resultados se deban al azar.

Análisis del R2

El coeficiente de determinación R^2 es de 0.7544, lo que indica que el 75.44% de la variación en el precio de los apartamentos se explica por las variables del modelo. Este es un valor alto, lo que indica que el modelo tiene un buen ajuste.

Actividad 4

Realice la validación de supuestos del modelo e interprete los resultados (no es necesario corregir en caso de presentar problemas, solo realizar sugerencias de que se podría hacer).

Gráfico Q-Q:

residuos <- resid(modelo2)
qqnorm(residuos)
qqline(residuos)

Los puntos se ajustan de manera razonable a la línea recta diagonal, lo que sugiere una distribución normal de los residuos del modelo, un supuesto fundamental en la regresión lineal. Sin embargo, se aprecia una leve curvatura en la parte superior derecha, lo que sugiere que algunos valores atípicos pueden estar ejerciendo una mayor influencia en la distribución de los residuos.

hist(residuos)

La imagen muestra que los residuos se encuentran cerca de cero, lo que indica que el modelo es preciso en la mayoría de las predicciones.

Prueba de Kolmogorov-Smirnov

ks.test(residuos, "pnorm")
## 
##  Asymptotic one-sample Kolmogorov-Smirnov test
## 
## data:  residuos
## D = 0.49308, p-value < 2.2e-16
## alternative hypothesis: two-sided

En este caso, el valor p es menor que el nivel de significancia usual (0.05), por lo que se puede rechazar la hipótesis nula de que los residuos se distribuyen normalmente.

Gráfico de dispersión de residuos estandarizados

# Crear el modelo de regresión (reemplaza 'modelo' con el nombre de tu modelo)
residuos <- resid(modelo2)
valores_ajustados <- predict(modelo2)

# Calcula los residuos estandarizados
residuos_estandarizados <- residuos / sd(residuos)

# Gráfico de dispersión de residuos estandarizados vs valores ajustados
plot(valores_ajustados, residuos_estandarizados, xlab = "Valores ajustados", ylab = "Residuos estandarizados", main = "Dispersión de Residuos Estándarizados vs Valores Ajustados")
abline(h = 0, col = "red")  # Agrega una línea horizontal en y = 0

Dispersión general: La mayoría de los puntos se encuentran dispersos aleatoriamente alrededor de la línea y = 0, lo que es un buen indicio.

Patrones específicos: Se aprecia una leve tendencia hacia una mayor variabilidad de los residuos para valores ajustados más altos, lo que sugiere la posible presencia de una heterocedasticidad leve. Además, se identifican algunos puntos atípicos que exceden el límite superior de +- 2 desviaciones estándar. Estas observaciones podrían originarse por errores de medición o por la presencia de valores atípicos dentro de la población.

Recomendación: Es importante identificar la causa de los puntos atípicos y decidir si se deben eliminar del análisis.

Prueba de Breusch-Pagan o prueba de White

library(lmtest)

# Prueba de Breusch-Pagan
bptest(modelo2)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo2
## BP = 929.2, df = 5, p-value < 2.2e-16
# Prueba de White
bptest(modelo2, studentize = FALSE)
## 
##  Breusch-Pagan test
## 
## data:  modelo2
## BP = 14378, df = 5, p-value < 2.2e-16

Ambas pruebas rechazan la hipótesis nula de homocedasticidad con un valor p muy pequeño (menor que 2.2e-16). Esto significa que hay una fuerte evidencia para concluir que existe heterocedasticidad en el modelo.

Recomendaciones para corregir la heterocedasticidad

Del mismo modo que sucede con las viviendas

Utilizar un modelo de regresión con ponderaciones: Asignar pesos a las observaciones para compensar la heterocedasticidad. Por ejemplo, se pueden utilizar ponderaciones por la varianza de los errores.

Transformar las variables: Transformar las variables para que la varianza de los errores sea más constante. Algunas transformaciones comunes son la transformación logarítmica o la raíz cuadrada.

Utilizar estimadores robustos: Estimar los coeficientes del modelo utilizando métodos que son menos sensibles a la heterocedasticidad. Algunos ejemplos de estimadores robustos son el estimador de mínimos cuadrados ponderados o el estimador M.

Prueba de Ausencia de multicolinealidad

library(car)

# Calcular el VIF para cada variable independiente en el modelo
vif <- vif(modelo2)
vif
##    areaconst      estrato habitaciones parqueaderos       banios 
##     2.027751     1.555176     1.441342     1.310740     2.470269

Todas las variables tienen valores de VIF menores a 10, lo que indica que no hay un problema de colinealidad entre las variables del modelo.

Actividad 5

Con el modelo identificado debe predecir el precio de la vivienda con las características de la segunda solicitud.

apartamento_5 <- data.frame(
  areaconst = 300,
  estrato = 5,
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)

apartamento_6 <- data.frame(
  areaconst = 300,
  estrato = 6,
  habitaciones = 5,
  parqueaderos = 3,
  banios = 3
)

prediccion_5 <- predict(modelo2, newdata = apartamento_5)
prediccion_6 <- predict(modelo2, newdata = apartamento_6)

resultado_5 <- sprintf(
  "El precio predicho para un apartamento estrato 5: %.0f", 
  prediccion_5
)

resultado_6 <- sprintf(
  "El precio predicho para un apartamento estrato 6: %.0f", 
  prediccion_6
)

print(resultado_5)
## [1] "El precio predicho para un apartamento estrato 5: 686"
print(resultado_6)
## [1] "El precio predicho para un apartamento estrato 6: 755"

Se utiliza el modelo para predecir el valor de apartamento con las características definidas, considerando los estratos 5 y 6 por separado.

Actividad 6

Con las predicciones del modelo sugiera potenciales ofertas que responda a la solicitud de la vivienda 2. Tenga encuenta que la empresa tiene crédito pre-aprobado de máximo 850 millones de pesos. Realice un análisis y presente en un mapa al menos 5 ofertas potenciales que debe discutir.

Se utiliza el precio predicho por el modelo para un apartamento de estrato 5, ya que representa el valor más bajo dentro de los requisitos establecidos para la vivienda de tipo 2.

ofertas_apartamentos <- subset(
  apartamentos_sur,
  preciom <= 850 &
  areaconst >= 300 &
  parqueaderos >= 3 &
  banios >= 3 &
  habitaciones >= 5 &
  estrato %in% c(5,6)
)

ofertas_apartamentos <- subset(
  ofertas_apartamentos[order(ofertas_apartamentos$preciom), ]
)

ofertas_apartamentos <- head(ofertas_apartamentos, 5)

ofertas_apartamentos
##      piso estrato preciom areaconst parqueaderos banios habitaciones longitud
## 6669    3       5     670       300            3      5            6  -76.550
## 3251    3       5     730       573            3      8            5  -76.548
##      latitud Centro Norte Oeste Oriente tipoCasa
## 6669   3.409      0     0     0       0        0
## 3251   3.408      0     0     0       0        0

Al buscar apartamentos que cumplan con las características descritas para la vivienda tipo 2, se encontraron dos opciones: uno con un precio de 670 y otro con un precio de 730. Se observa que ambos precios son similares a los valores predichos por el modelo para apartamentos de estrato 6 y 5.

A continuación, se presenta el mapa con los registros filtrados:

library(leaflet)

mapa <- leaflet() %>%
  addTiles()

mapa%>%
  addMarkers(
    data = ofertas_apartamentos, 
    lng = ~longitud, 
    lat = ~latitud,
    popup = paste("Precio:", ofertas_apartamentos$preciom, "$", 
                           "<br>Habitaciones:", ofertas_apartamentos$habitaciones,
                           "<br>Baños:", ofertas_apartamentos$banios)
)