prec_ecop=c(1090, 1170, 1160, 1230, 1155, 1165, 1205, 1170, 1150, 1130, 1110, 1105, 1085, 1060, 1035, 1015, 955, 961)
prec_petr=c(35.62,36.31,37.35,34.95,34.53,35.81,36.14,37.50,37.80,36.81,37.87,37.04,36.76,35.97,33.97,33.27,31.41,30.44)
data_petrol = data.frame(prec_ecop,prec_petr)
library(ggplot2)
require(plotly)
g1 = ggplot(data = data_petrol, aes(y = prec_ecop, x = prec_petr)) + geom_point() + geom_smooth()
ggplotly(g1)
model_ep = lm(prec_ecop~prec_petr)
summary(model_ep)
##
## Call:
## lm(formula = prec_ecop ~ prec_petr)
##
## Residuals:
## Min 1Q Median 3Q Max
## -59.90 -40.74 -15.94 33.40 136.82
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 177.768 232.828 0.764 0.45627
## prec_petr 26.192 6.542 4.004 0.00102 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 57.13 on 16 degrees of freedom
## Multiple R-squared: 0.5005, Adjusted R-squared: 0.4692
## F-statistic: 16.03 on 1 and 16 DF, p-value: 0.001024
Observamos que al aplicar una regresión lineal simple a la base de datos, obtenemos un R Cuadrado de 0.5. Este valor representa un mal ajuste con respecto a los datos disponibles. Por tal motivo, aplicaremos una transformación al modelo para mejorar su ajuste. Teniendo en cuenta la gráfica obtenida durante el análisis exploratorio y un proceso de prueba y error, utilizaremos una transformación “Doble Logarítmo”.
model_ep_log = lm(log(prec_ecop)~log(prec_petr))
summary(model_ep_log)
##
## Call:
## lm(formula = log(prec_ecop) ~ log(prec_petr))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.05435 -0.03615 -0.01306 0.02928 0.11927
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.9229 0.7072 5.547 4.42e-05 ***
## log(prec_petr) 0.8646 0.1981 4.364 0.000482 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.05048 on 16 degrees of freedom
## Multiple R-squared: 0.5434, Adjusted R-squared: 0.5149
## F-statistic: 19.04 on 1 and 16 DF, p-value: 0.0004824
Según la regresión estimada tenemos los siguientes parámetros:
β0: 3.9229 β1: 0.8646
log(y) = 0.8646*log(x) + 3.9229
Donde:
Y: Precio Acción Ecopetrol (COP)
X: Precio Barril Petroleo WTI (USD)
El valor del R cuadrado es de 0.5434 lo cual nos indica que la recta del modelo estimado tiene un ajuste regular con respecto a los datos.
A pesar de que el cambio en R Cuadrado no es tan significativo, si se obtiene un mejor ajuste que con el modelo inicial.
H0 : El precio del petróleo no es significativo para estimar el precio de la acción de Ecopetrol
H1 : El precio del petróleo sí es significativo para estimar el precio de la acción de Ecopetrol
Verificando el resultado de la función summary aplicado al modelo anterior, podemos observar que el p-value de β1 es menor que 0.05 (0.000482). Por tal motivo rechazamos la hipótesis nula. Podemos concluir que el precio del petróleo es significativo en relación al precio de la acción de Ecopetrol.
El signo de β1 nos muestra que existe una relación positiva entre el precio del petróleo y la acción de Ecopetrol dentro de los datos disponibles.
En escala Doble Logarítmica, la magnitud de β1 muestra que hay un incremento de 0.8646 veces por cada unidad en el precio del petróleo.
mean(model_ep_log$residuals) # Promedio de residuos
## [1] 3.998654e-18
shapiro.test(model_ep_log$residuals) # Normalidad de errores
##
## Shapiro-Wilk normality test
##
## data: model_ep_log$residuals
## W = 0.89906, p-value = 0.05534
lmtest::bptest(model_ep_log) # Varianza constante de los errores
##
## studentized Breusch-Pagan test
##
## data: model_ep_log
## BP = 0.014709, df = 1, p-value = 0.9035
lmtest::dwtest(model_ep_log) # No autocorrelación de errores
##
## Durbin-Watson test
##
## data: model_ep_log
## DW = 0.73303, p-value = 0.0004053
## alternative hypothesis: true autocorrelation is greater than 0
Teniendo en cuenta el resultado de la prueba Durbin-Watson podemos concluir que el modelo no cumple con el supuesto de Autocorrelación de residuales. Por lo cual no podemos confirmar que exista una relación lineal en los datos disponibles y la validez del modelo propuesto.
Teniendo en cuenta el análisis realizado a lo largo de este punto podemos llegar a las siguientes conclusiones:
Hay evidencias de una relación positiva entre precio del barril de petróleo y la acción de Ecopetrol
El modelo planteado solo explica una porción del precio del barril. Para mejorar el modelo se deberían incluir más variables a la regresión.
La relación entre precio del barril y la acción de Ecopetrol NO es lineal.
infl=c(9.23, 8.75, 7.65, 6.99, 6.49, 5.50, 4.85, 4.48, 5.69, 7.67, 2.00, 3.17, 3.73, 2.44, 1.94, 3.66, 6.77)
smlm=c(236460, 260100, 286000, 309000, 332000, 358000, 381500, 408000, 433700, 461500, 496900, 515000, 535600, 566700, 589500, 616027, 644350)
data_inflacion = data.frame(infl,smlm)
cambio_salario = c(NA,100*(diff(data_inflacion$smlm)/head(smlm,-1))) # Calcular cambio de salario en porcentaje
data_inflacion$cambio_salario = cambio_salario # Incluir cambio de salario a dataframe
data_inflacion = data_inflacion[-c(1),] # Eliminar primera observación, no se cuenta con dato de cambio de salario
g1 = ggplot(data = data_inflacion, aes(y = cambio_salario, x = infl)) + geom_point() + geom_smooth()
ggplotly(g1)
Para este punto, se analiza qué efecto tiene la inflación en el salario minimo legal de Colombia. Teniendo en cuenta que lo que se busca identificar es el cambio (Delta) en salario, se realiza primero una transformación de la BD para incluir una columna del cambio de salario anualmente (%). En la gráfica anterior, podemos observar la relación entre inflación (%) y cambio de salario interanual (%). Podemos observar una relación positiva entre ambas variables y cierta tendencia lineal en esta relación. Sin embargo, se necesita más análisis para hacer conclusiones.
model_salario = lm(data_inflacion$cambio_salario~data_inflacion$infl)
summary(model_salario)
##
## Call:
## lm(formula = data_inflacion$cambio_salario ~ data_inflacion$infl)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.8423 -1.2470 0.1983 0.9290 2.9818
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.5353 1.0613 3.331 0.00495 **
## data_inflacion$infl 0.5768 0.1922 3.001 0.00953 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.608 on 14 degrees of freedom
## Multiple R-squared: 0.3915, Adjusted R-squared: 0.3481
## F-statistic: 9.008 on 1 and 14 DF, p-value: 0.009526
Según la regresión estimada tenemos los siguientes parámetros:
β1: 0.5768 β0: 3.5353
y = 3.5353 + 0.5768*x
Donde x es el porcentaje de inflación anual (%).
y es el porcentaje de incremento en el salario mínimo con respecto al año anterior.
mean(model_salario$residuals)
## [1] -2.428613e-17
shapiro.test(model_salario$residuals) # Normalidad de errores
##
## Shapiro-Wilk normality test
##
## data: model_salario$residuals
## W = 0.98464, p-value = 0.9898
lmtest::bptest(model_salario) # Varianza constante de los errores
##
## studentized Breusch-Pagan test
##
## data: model_salario
## BP = 0.04693, df = 1, p-value = 0.8285
lmtest::dwtest(model_salario) # No autocorrelación de errores
##
## Durbin-Watson test
##
## data: model_salario
## DW = 1.7203, p-value = 0.2236
## alternative hypothesis: true autocorrelation is greater than 0
De acuerdo a las pruebas realizadas anteriormente se pueden validar los supuestos correspondientes al modelo propuesto.
Con respecto al p-value del B1 del modelo (0.00953), este nos demuestra que la variable inflación es representativa para explicar variaciones en el salario mínimo en Colombia.
cor(data_inflacion$infl,data_inflacion$cambio_salario)
## [1] 0.6257148
El coeficiente de correlación entre la inflación y el cambio de salario es de 0.625. Este valor refleja una relación lineal positiva debil.
El coeficiente de determinación (R cuadrado) del modelo es de 0.3915 lo cual refleja un mal ajuste de la recta con respecto a los datos disponibles.
El β1 del modelo propuesto refleja que hay una relación positiva entre inflación y cambio en el salario interanual. Un incremento en 1 punto porcentual de inflación implicaría un incremento de 0.5768 % en el salario mínimo.
El β0 del modelo refleja que hay un incremento base o no explicado por la inflación de 3.5353 %.
par(mfrow=c(2,2))
plot(model_salario)
Mediante el método gráfico podemos validar los cálculos realizados en el inciso B) donde confirmamos que se cumplen los supuestos del modelo.
library(readxl)
Datos_Vivienda <- read_excel("C:/Users/agiac/Desktop/Maestria Data Science/2 Semestre/data/Datos_Vivienda.xlsx")
vivienda_zona_norte <- subset(Datos_Vivienda, Zona == "Zona Norte" & precio_millon < 500 & Area_contruida < 300)
head(vivienda_zona_norte,3)
| Zona | piso | Estrato | precio_millon | Area_contruida | parqueaderos | Banos | Habitaciones | Tipo | Barrio | cordenada_longitud | Cordenada_latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Zona Norte | 2 | 3 | 135 | 56 | 1 | 1 | 3 | Apartamento | torres de comfandi | -76.46745 | 3.40763 |
| Zona Norte | NA | 5 | 400 | 212 | NA | 2 | 4 | Casa | santa mv=nica residencial | -76.47300 | 3.41800 |
| Zona Norte | NA | 3 | 78 | 54 | 2 | 1 | 3 | Apartamento | chiminangos | -76.47820 | 3.44898 |
library(tidyverse)
require(leaflet)
leaflet() %>% addCircleMarkers(lng= vivienda_zona_norte$cordenada_longitud, lat = vivienda_zona_norte$Cordenada_latitud, radius = 0.3, color = "black") %>% addTiles()
Podemos observar en el mapa que hay viviendas fuera de la zona norte que fueron incluidas en la base de datos con la zona equivocada. Por ese motivo, se presentan en la gráfica. Se debería hacer una revisión mediante coordenadas (latitud, longitud) para filtrar la base de datos más eficientemente (si está disponible)
Variables_analisis = select(vivienda_zona_norte, precio_millon, Area_contruida, parqueaderos, Estrato)
summary(Variables_analisis)
## precio_millon Area_contruida parqueaderos Estrato
## Min. : 65.0 Min. : 30.0 Length:1483 Min. :3.000
## 1st Qu.:145.0 1st Qu.: 64.0 Class :character 1st Qu.:3.000
## Median :240.0 Median : 88.0 Mode :character Median :4.000
## Mean :247.2 Mean :106.5 Mean :4.084
## 3rd Qu.:335.0 3rd Qu.:125.0 3rd Qu.:5.000
## Max. :495.0 Max. :297.0 Max. :6.000
El precio promedio de una vivienda en el norte de Cali es de 247.2 millones de pesos.
El precio de la vivienda en el norte de Cali está entre los 65 a 495 millones.
La media del área construida (m2) en el norte de Cali es de 88 m2.
La vivienda media en el norte de Cali cuenta con 1 parqueadero.
No hay viviendas de estrato 1 o 2 en el norte de Cali.
library(inspectdf)
prueba = data.frame(vivienda_zona_norte$precio_millon,vivienda_zona_norte$Area_contruida,vivienda_zona_norte$Estrato,vivienda_zona_norte$parqueaderos)
prueba %>%
inspect_cor(with_col = "vivienda_zona_norte.precio_millon") %>%
show_plot()
De acuerdo a la gráfica anterior, podemos observar que la variable con
una correlación más fuerte con respecto al precio de la vivienda es el
estrato.
Por otro lado, el número de parqueaderos es el de menor impacto en el precio de la vivienda.
vivienda_zona_norte$parqueaderos = as.numeric(vivienda_zona_norte$parqueaderos)
vivienda_zona_norte[is.na(vivienda_zona_norte)] <- 0
model_vivienda = lm(precio_millon~Area_contruida+Estrato+parqueaderos,data = vivienda_zona_norte)
summary(model_vivienda)
##
## Call:
## lm(formula = precio_millon ~ Area_contruida + Estrato + parqueaderos,
## data = vivienda_zona_norte)
##
## Residuals:
## Min 1Q Median 3Q Max
## -197.551 -35.912 -4.441 28.393 297.410
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -125.39846 6.97843 -17.969 < 2e-16 ***
## Area_contruida 0.84752 0.02839 29.856 < 2e-16 ***
## Estrato 65.71241 1.80128 36.481 < 2e-16 ***
## parqueaderos 15.55661 2.04374 7.612 4.79e-14 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 57.44 on 1479 degrees of freedom
## Multiple R-squared: 0.7313, Adjusted R-squared: 0.7308
## F-statistic: 1342 on 3 and 1479 DF, p-value: < 2.2e-16
Según la regresión lineal múltiple ajustada tenemos los siguientes parámetros:
β Area_contruida: 0.84752
β Estrato: 65.71241 β parqueaderos: 15.55661 β0 = -125.39846
Teniendo como ecuación del modelo:
precio_millon = (0.84752 * Area_contruida) + (65.71241 * Estrato) + (15.55661 * parqueaderos) -125.39846
El R Cuadrado del modelo es de 0.7313, lo cual refleja que el modelo tiene un buen ajuste con respecto a los datos disponibles.
Considero que para mejorar este modelo se pueden realizar los siguientes pasos adicionales:
Utilizar una variable “Dummy” para transformar la columna Estrato. Ya que no es una variable cuantitativa, esta podría afectar el ajuste del modelo.
Posiblemente se podría aplicar una transformación al modelo en busqueda de un mejor R Cuadrado.
Se debería revisar qué variables aparte de las incluidas en el modelo podrían tener una correlación fuerte con respecto al precio. Se podría plantear incluir una nueva variable o reemplazar alguna de las ya incluidas. Por ejemplo, número de habitaciones podría tener un coeficiente de correlación más fuerte que el número de habitaciones.
par(mfrow=c(2,2))
plot(model_vivienda)
De acuerdo a la validación por método gráfico se podrían validar los supuestos del modelo.
predict(model_vivienda, list(Area_contruida=100,Estrato=4,parqueaderos=1),interval = "confidence")
## fit lwr upr
## 1 237.7599 234.7492 240.7707
De acuerdo a el modelo propuesto, una vivienda con las especificaciones anteriores en la zona Norte de Cali debería rondar entre los 237 a 241 millones (con un intervalo de confianza del 95%), por tal motivo considero que sería una mala oferta.
vivienda_muestra = subset(vivienda_zona_norte, precio_millon <=400 & Area_contruida >100 & Estrato == 4 & parqueaderos > 0)
head(vivienda_muestra,5)
| Zona | piso | Estrato | precio_millon | Area_contruida | parqueaderos | Banos | Habitaciones | Tipo | Barrio | cordenada_longitud | Cordenada_latitud |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Zona Norte | 2 | 4 | 265 | 162 | 1 | 3 | 4 | Casa | zona norte | -76.48238 | 3.46786 |
| Zona Norte | NA | 4 | 250 | 115 | 1 | 3 | 3 | Casa | villa del sol | -76.49500 | 3.48300 |
| Zona Norte | 2 | 4 | 330 | 165 | 1 | 4 | 4 | Casa | el bosque | -76.49657 | 3.45140 |
| Zona Norte | 2 | 4 | 370 | 240 | 2 | 5 | 5 | Casa | el bosque | -76.50000 | 3.46800 |
| Zona Norte | 2 | 4 | 350 | 280 | 2 | 3 | 4 | Casa | la merced | -76.50603 | 3.46643 |
summary(vivienda_muestra)
## Zona piso Estrato precio_millon
## Length:64 Length:64 Min. :4 Min. :185.0
## Class :character Class :character 1st Qu.:4 1st Qu.:278.8
## Mode :character Mode :character Median :4 Median :320.0
## Mean :4 Mean :313.0
## 3rd Qu.:4 3rd Qu.:350.0
## Max. :4 Max. :397.0
## Area_contruida parqueaderos Banos Habitaciones
## Min. :103.0 Min. :1.000 Min. :2.000 Min. :0.000
## 1st Qu.:124.5 1st Qu.:1.000 1st Qu.:2.000 1st Qu.:3.000
## Median :159.2 Median :1.500 Median :3.000 Median :4.000
## Mean :177.0 Mean :1.562 Mean :3.031 Mean :3.781
## 3rd Qu.:240.0 3rd Qu.:2.000 3rd Qu.:4.000 3rd Qu.:4.000
## Max. :295.0 Max. :4.000 Max. :5.000 Max. :7.000
## Tipo Barrio cordenada_longitud Cordenada_latitud
## Length:64 Length:64 Min. :-76.55 Min. :3.376
## Class :character Class :character 1st Qu.:-76.53 1st Qu.:3.464
## Mode :character Mode :character Median :-76.52 Median :3.478
## Mean :-76.52 Mean :3.469
## 3rd Qu.:-76.51 3rd Qu.:3.483
## Max. :-76.48 Max. :3.491
muestra_1 = head(vivienda_muestra,5)
require(leaflet)
leaflet() %>% addCircleMarkers(lng= muestra_1$cordenada_longitud, lat = muestra_1$Cordenada_latitud, radius = 0.3, color = "black") %>% addTiles()
library(readxl)
data_arboles <- read_excel("C:/Users/agiac/Desktop/Maestria Data Science/2 Semestre/data/data_arboles.xlsx",
col_types = c("text", "text", "numeric",
"numeric", "numeric"))
boxplot(data_arboles$peso~data_arboles$finca,ylab = "pesos del árbol",xlab = "finca")
boxplot(data_arboles$peso~data_arboles$mg,ylab = "pesos del árbol",xlab = "genotipo")
De acuerdo a los diagramas de cajas y bigotes, podemos observar que hay una efecto de ambas variables cualitativas (finca y genotipo) sobre el peso del arbol incluidos en la base de datos disponible. Por este motivo, decidimos incluirlo en el modelo de regresión lineal. Por otro lado, incluimos el diámetro y altura total del arbol ya que el volumen de un solido (asumiendo forma cilíndrica) está dado por estas dos dimensiones.
dt = sort(sample(nrow(data_arboles), nrow(data_arboles)*.7))
data_arboles_model<-data_arboles[dt,] # Conjunto de datos para modelo
data_arboles_test<-data_arboles[-dt,] # Conjunto de datos para test
mod_peso_arb = lm(log(peso) ~ diametro + altura + finca + mg , data = data_arboles_model)
summary(mod_peso_arb)
##
## Call:
## lm(formula = log(peso) ~ diametro + altura + finca + mg, data = data_arboles_model)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.199358 -0.047182 -0.005563 0.057348 0.173658
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.00692 0.07102 14.178 < 2e-16 ***
## diametro 0.19394 0.02637 7.355 8.97e-10 ***
## altura 0.13164 0.02751 4.785 1.29e-05 ***
## fincaFINCA_2 -0.02875 0.03810 -0.755 0.454
## fincaFINCA_3 0.21871 0.02845 7.688 2.52e-10 ***
## mgGENOTIPO_2 -0.28716 0.04816 -5.963 1.75e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08582 on 56 degrees of freedom
## Multiple R-squared: 0.9612, Adjusted R-squared: 0.9577
## F-statistic: 277.1 on 5 and 56 DF, p-value: < 2.2e-16
En el modelo propuesto tenemos un R Cuadrado de 0.9633 lo cual refleja un muy buen ajuste del modelo con respecto a los datos disponibles.
Modelo:
Finca 1, Genotipo 1 -> log(peso) = 1.03316 + (0.23155 * Diámetro) + (0.09509 * Altura)
Finca 1, Genotipo 2 -> log(peso) = (1.03316 - 0.25046) + (0.23155 * Diámetro) + (0.09509 * Altura)
Finca 2, Genotipo 1 -> log(peso) = (1.03316 - 0.05019) + (0.23155 * Diámetro) + (0.09509 * Altura)
Finca 2, Genotipo 2 -> log(peso) = (1.03316 - 0.05019 - 0.25046) + (0.23155 * Diámetro) + (0.09509 * Altura)
Finca 3, Genotipo 1 -> log(peso) = (1.03316 + 0.20800) + (0.23155 * Diámetro) + (0.09509 * Altura)
Finca 3, Genotipo 2 -> log(peso) = (1.03316 + 0.20800 - 0.25046) + (0.23155 * Diámetro) + (0.09509 * Altura)
Podemos observar que las variables seleccionadas son significativas de acuerdo al summary del modelo (p-value menores que 0.05).
El B1 correspondiente al diámetro tiene mayor impacto sobre el peso en comparación a la altura.
Hacemos una predicción para verificar funcionamiento del modelo:
prueba = data.frame(diametro=6.1, finca = "FINCA_2", altura = 7.6, mg = "GENOTIPO_2")
ln_peso_estimado = predict(mod_peso_arb,newdata = prueba)
peso_estimado = exp(ln_peso_estimado)
peso_estimado
## 1
## 17.71724
library(caret)
predicciones <- exp(predict(mod_peso_arb,newdata = data_arboles_test))
data.frame(R_squared = R2 (predicciones, data_arboles_test$peso),RMSE = RMSE(predicciones, data_arboles_test$peso),MAE = MAE(predicciones,data_arboles_test$peso))
| R_squared | RMSE | MAE |
|---|---|---|
| 0.9440883 | 2.159962 | 1.418155 |