1 Carga de paquetes

library(tidyverse)
library(readxl)

2 Carga de base de datos

#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

3 Visualización de datos

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")

3.1 Preparación de los datos

Se crea una variable binaria llamada DUMMY para representar la variedad:

  • 1: “Criolla”
  • 0: “Clementina”
# 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
table(MANDARINAS_CON_DUMMY$DUMMY)
## 
##   0   1 
## 209 210

4 Ajuste del modelo

4.1 Ecuación de la Regresión Logística

\[log(p/1-p) = β0 + β1 * X\] donde “p” es la probabilidad de que una mandarina sea de la variedad “Criolla”.

4.2 Función en R

La función glm() en R permite ajustar Modelos Lineales Generalizados (GLM), que extienden la regresión lineal para permitir:

  • Variables respuesta con distribuciones diferentes de la normal (binomial, Poisson, etc.).
  • Relación no lineal entre la media y los predictores.
  • Sintaxis:

glm(formula(ejemplo: Y~X), family = (binomial, poisson, etc) , data = BASE_DE_DATOS)

4.3 Modelado con 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

5 Evaluación del modelo

5.1 Ecuación del modelo ajustado

\[log (p/1-p) = 2.535767 - 0.017861 * PESO\]

5.2 Coeficientes y Odds Ratio

MODELO_REG_LOG_PESO$coefficients
## (Intercept)        PESO 
##  2.53576690 -0.01786136

Interpretación:

  • Intercepto (β₀ = 2.535767): log-odds de ser Criolla cuando el peso es 0 (sin relevancia práctica).
  • PESO (β₁ = -0.017861): cada gramo adicional de peso disminuye los log-odds de ser Criolla en 0.0179.
exp(MODELO_REG_LOG_PESO$coefficients)
## (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).

  • Cálculo del porcentaje de cambio en los odds La fórmula general es:

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).

  • Por cada gramo adicional, las probabilidades de que una mandarina sea de la variedad Criolla disminuyen 1.8 %.

6 Diagnóstico del modelo

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.

  • Desviancia nula: 580.85 (desviancia sin predictor)
  • Desviancia residual: 542.34 (desvianza del modelo que incluye al predictor)
  • Reducción: 38.51 (indica que al incluir el predictor PESO mejora el ajuste)

Criterio de información de Akaike:

  • AIC: 546.34

Hipótesis estadística para β1:

H₀: β1 = 0

  • El predictor PESO no tiene efecto sobre la probabilidad de que una mandarina sea de la variedad Criolla.

H₁: β1 ≠ 0

  • El predictor PESO sí tiene efecto sobre esa probabilidad (puede ser positivo o negativo).

Como p-valor para β₁: 7.15e-09*** (El peso tiene un efecto significativo en la probabilidad de que una mandarina sea Criolla.)

7 Visualización del modelo

# 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.

8 Cálculo de probabilidades

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?

  • Si el resultado es 0.46, significa que hay un 46% de probabilidad de que una fruta de 150 g sea Criolla.
  • La ventaja de este enfoque es que permite ver no solo la decisión final, sino cuán probable es que una fruta sea de una u otra variedad.

9 Matriz de confusión

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.

9.0.1 Conclusiones generales

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

  • El modelo clasifica correctamente aproximadamente

\[(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.

10 Diámetro ecuatorial como predictor de la variedad

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
exp(MODELO_REG_LOG_DIAM$coefficients)
##  (Intercept)   DIAM_ECUAT 
## 1652.9182443    0.8968493

10.1 Comparación de modelos logísticos con diámetro ecuatorial vs peso

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%

10.1.1 Interpretación y elección del modelo

Ambos modelos son estadísticamente significativos, pero el modelo con diámetro ecuatorial (DIAM_ECUAT) presenta mejores indicadores:

  • Reduce más la desviancia residual > capacidad explicativa.
  • Tiene un AIC más bajo, indicando mejor ajuste.
  • El efecto del predictor es más fuerte: por cada milímetro adicional de diámetro, los odds de que la mandarina sea de variedad Criolla disminuyen un 10.3 %, mientras que por cada gramo adicional de peso, los odds se reducen solo en un 1.8 %.