#Utilizaremos la base de datos `MANDARINAS_2024`
MANDARINAS <- read_excel("MANDARINAS_2024.xlsx")
head(MANDARINAS)## # A tibble: 6 × 8
## N GRUPO VARIEDAD N_DE_FRUTO PESO DIAM_ECUAT NIVEL_DE_DAÑO COLOR
## <dbl> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1 Clementina 19 101 64.2 1 4
## 2 2 1 Clementina 9 122 64.2 0 5
## 3 3 1 Clementina 21 127 64.7 3 4
## 4 4 1 Clementina 8 126 64.9 3 1
## 5 5 1 Clementina 4 37 65.9 2 5
## 6 6 1 Clementina 30 139 66.4 2 4
ggplot(MANDARINAS, aes(x = VARIEDAD, y = PESO, fill = VARIEDAD)) +
geom_boxplot(alpha = 0.6) + # No duplicar puntos con jitter
geom_jitter(width = 0.06, alpha = 0.4, size = 1.5) +
labs(title = "Distribución del diámetro ecuatorial según la variedad de mandarina",
x = "Variedad",
y = "Peso (g)") +
theme_minimal() +
theme(legend.position = "none")Se crea una variable binaria llamada DUMMY para representar la variedad:
# Crear variable binaria para la regresión
MANDARINAS_CON_DUMMY <- MANDARINAS %>%
mutate(DUMMY = if_else(VARIEDAD == "Criolla", 1, 0))
# mutate crea una nueva columna llamada "CRIOLLA"
# Si VARIEDAD es "Criolla", asigna 1; en caso contrario, asigna 0.
head(MANDARINAS_CON_DUMMY)## # A tibble: 6 × 9
## N GRUPO VARIEDAD N_DE_FRUTO PESO DIAM_ECUAT NIVEL_DE_DAÑO COLOR DUMMY
## <dbl> <dbl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 1 Clementina 19 101 64.2 1 4 0
## 2 2 1 Clementina 9 122 64.2 0 5 0
## 3 3 1 Clementina 21 127 64.7 3 4 0
## 4 4 1 Clementina 8 126 64.9 3 1 0
## 5 5 1 Clementina 4 37 65.9 2 5 0
## 6 6 1 Clementina 30 139 66.4 2 4 0
##
## 0 1
## 209 210
\[log(p/1-p) = β0 + β1 * X\] donde “p” es la probabilidad de que una mandarina sea de la variedad “Criolla”.
La función glm() en R permite ajustar Modelos Lineales Generalizados (GLM), que extienden la regresión lineal para permitir:
glm(formula(ejemplo: Y~X), family = (binomial, poisson, etc) , data = BASE_DE_DATOS)
glm()MODELO_REG_LOG_PESO <- glm(DUMMY ~ PESO, family = binomial, data = MANDARINAS_CON_DUMMY)
summary(MODELO_REG_LOG_PESO)##
## Call:
## glm(formula = DUMMY ~ PESO, family = binomial, data = MANDARINAS_CON_DUMMY)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.535767 0.449079 5.647 1.64e-08 ***
## PESO -0.017861 0.003086 -5.787 7.15e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 580.85 on 418 degrees of freedom
## Residual deviance: 542.34 on 417 degrees of freedom
## AIC: 546.34
##
## Number of Fisher Scoring iterations: 4
\[log (p/1-p) = 2.535767 - 0.017861 * PESO\]
## (Intercept) PESO
## 2.53576690 -0.01786136
Interpretación:
## (Intercept) PESO
## 12.6261101 0.9822972
Cuando el predictor es cuantitativo continuo (como el peso), el Odds Ratio no compara “Grupo A vs Grupo B”, sino el efecto de incrementar una unidad en esa variable.
En este caso, compara las chances de que una mandarina sea de la variedad Criolla entre dos frutas que difieren en 1 gramo de peso.
Interpretación:
Si el OR = 1 (no hay efecto del predictor sobre el resultado).
Si el OR > 1 (el predictor aumenta los odds y la probabilidad del evento).
Si el OR < 1 (el predictor disminuye los odds y la probabilidad del evento).
Cambio porcentual = (Odds Ratio−1) * 100
El odds ratio de peso es 0.982
Entonces: (0.982−1) * 100 = −1.77% ≈ −1.8% (El 1 representa el valor de referencia del odds ratio).
Deviancia: La deviancia en regresión logística es una medida que indica qué tan bien se ajusta el modelo a los datos. Cuanto menor es la deviancia, mejor es el ajuste del modelo a los datos observados. Sirve para comparar modelos: si agregás una variable y la deviancia baja mucho, es señal de que esa variable mejora el modelo.
Criterio de información de Akaike:
Hipótesis estadística para β1:
H₀: β1 = 0
H₁: β1 ≠ 0
Como p-valor para β₁: 7.15e-09*** (El peso tiene un efecto significativo en la probabilidad de que una mandarina sea Criolla.)
# Base de puntos observados
ggplot(MANDARINAS_CON_DUMMY, aes(PESO, DUMMY)) +
geom_point( alpha = 0.2) +
stat_smooth(method = "glm", method.args = list(family = "binomial"), # Curva logística ajustada por el modelo
se = FALSE, color = "blue", size = 1.2) +
labs(x = "Peso (g)",
y = "Probabilidad") +
theme_minimal()| Argumento | ¿Para qué sirve? |
|---|---|
| `method = “glm”` | indica a ggplot2 que debe usar un modelo lineal
generalizado (glm) |
| `method.args = list(family = “binomial”)` | Especifica que el modelo glm debe ser de
tipo binomial, es decir, regresión
logística. |
Recordemos:
El modelo No clasifica directamente como 0 o 1 (Clementina o Criolla). En cambio, calcula la probabilidad de que el evento ocurra (sea Criolla). + Se clasifica según un umbral (generalmente 0.5 o 50 %).
Vamos a calcular la probabilidad de que una fruta de un peso determinado ( 50, 100, 150 y 200 gramos) sea de la variedad Criolla.
# Crear un data frame con los pesos
PESOS_FRUTAS <- data.frame(PESO = c(50, 100, 150, 200))
# Probabilidades
predicciones <- predict(MODELO_REG_LOG_PESO, newdata =PESOS_FRUTAS, type = "response")
predicciones## 1 2 3 4
## 0.8379018 0.6790982 0.4642019 0.2618248
# Clasificación según umbral 0.5
clasificacion <- ifelse(predicciones > 0.5, "Criolla", "Clementina")
clasificacion## 1 2 3 4
## "Criolla" "Criolla" "Clementina" "Clementina"
| Argumento | ¿Para qué sirve? |
|---|---|
| `predict(…)` | función genérica de R que predice valores usando un
modelo ajustado, en este caso un modelo de glm. |
MODELO_REG_LOG_PESO` |
Modelo de regresión logística ya ajustado,
con DUMMY ~ PESO como fórmula. |
| `newdata = PESOS_FRUTAS` | Indica los nuevos datos sobre los que querés hacer
la predicción. Tiene que ser un data.frame con una columna
llamada PESO (para que coincida con el modelo). |
type = "response"` |
Esto le indica a predict() que devuelva
la probabilidad estimada (en vez de la predicción en
escala logit, que sería el valor de log(p / (1 - p))). |
¿Cómo interpretar ese valor?
Una matriz de confusión compara las clasificaciones predichas por el modelo con las observaciones reales.
Estructura:
| Observado: Clementina (0) | Observado: Criolla (1) | |
|---|---|---|
| Predicho: Clementina (0) | Verdadero Negativo | Falso Negativo |
| Predicho: Criolla (1) | Falso Positivo | Verdadero Positivo |
# Predicciones como probabilidades
probabilidades <- predict(MODELO_REG_LOG_PESO, type = "response")# calcula la probabilidad de que sea 1(Criolla) según el modelo
# Clasificación usando umbral 0.5
pred_clasificacion <- ifelse(probabilidades > 0.5, 1, 0)
# Matriz de confusión
table(Predicho = pred_clasificacion, Observado = MANDARINAS_CON_DUMMY$DUMMY)## Observado
## Predicho 0 1
## 0 131 89
## 1 78 121
Verdadero Positivo (VP): 121 mandarinas Criollas correctamente clasificadas.
Falso Positivo (FP): 78 mandarinas Clementinas clasificadas incorrectamente como Criollas.
Verdadero Negativo (VN): 131 mandarinas Clementinas correctamente clasificadas.
Falso Negativo (FN): 89 mandarinas Criollas clasificadas incorrectamente como Clementinas.
Para obtener el porcentaje de aciertos (accuracy) de la matriz de confusión del modelo calculamos:
Accuracy = ((Verdaderos Positivos (TP) + Verdaderos Negativos (TN)) / Total de observaciones) * 100
\[(121+131)/(121+78+89+131) = (252/419)*100 ≈ 60.1%121+78+89+131121+131=419252≈60.1 \]
Esto es la exactitud global del modelo.
El modelo tiene un rendimiento moderado (60.1 %), con errores importantes tanto al predecir Criolla como Clementina.
La cantidad relativamente alta de falsos positivos (78) y falsos negativos (89) sugiere que el modelo podría mejorar, quizá incluyendo más variables predictoras o ajustando el umbral de clasificación.
MODELO_REG_LOG_DIAM <- glm(DUMMY ~ DIAM_ECUAT, data = MANDARINAS_CON_DUMMY, family = binomial)
summary(MODELO_REG_LOG_DIAM)##
## Call:
## glm(formula = DUMMY ~ DIAM_ECUAT, family = binomial, data = MANDARINAS_CON_DUMMY)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 7.41030 1.19231 6.215 5.13e-10 ***
## DIAM_ECUAT -0.10887 0.01742 -6.251 4.08e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 580.85 on 418 degrees of freedom
## Residual deviance: 534.10 on 417 degrees of freedom
## AIC: 538.1
##
## Number of Fisher Scoring iterations: 4
## (Intercept) DIAM_ECUAT
## 1652.9182443 0.8968493
| Métrica | Modelo con peso | Modelo con diámetro |
|---|---|---|
| Intercepto | 2.536 | 7.41030 |
| Coeficiente predictor | -0.01786 | -0.10887 |
| Valor p | 7.15e-09*** | 4.08e-10*** |
| Null deviance | 580.85 | 580.85 |
| Residual deviance | 542.34 | 534.10 |
| Diferencia | 38.51 | 46.75 |
| AIC | 546.34 | 538.1 |
| Odds Ratio. | 0.982 | 0.897 |
| Cambio porcentual. | −1.8% | -10.3% |
| Interpretación | Cada gramo adicional reduce odds 1.8% | Cada mm extra reduce odds 10.3% |
Ambos modelos son estadísticamente significativos, pero el modelo con diámetro ecuatorial (DIAM_ECUAT) presenta mejores indicadores: