Tarea de Estadística Forense 2025

## Defino mi directorio de trabajo
setwd("~/Documents/Estadistica")
##Abriendo paquete pacman
library(pacman)
## El archivo esta en formato SPSS, lo abrimos mediante la libreria haven ## MASS permite analisis discriminante
p_load(haven,dplyr,ggplot2,MASS)
p_load(haven,dplyr,ggplot2,tinytex,tidyr, GGally)
Hombro <- read_sav("Datos hombro.sav")

## Definimos como factor la variable sexoN
Hombro$sexoN <- factor(Hombro$sexoN,
                       levels = c(1, 2), 
                       labels = c("Hombre", "Mujer"))
table (Hombro$sexoN)  ## Frecuencias de sexo
## 
## Hombre  Mujer 
##     50     30
# Omitimos los NA de la tabla
HombroS <- na.omit(Hombro[, c("sexoN", "LMCD","C12CD")])

# Para resumir por sexo la información de Longitud Maxima de clavicula derecha
        
    res_lmcd <- Hombro %>%
          group_by(sexoN) %>%
          summarise(
            n       = sum(!is.na(LMCD)),
            media   = mean(LMCD, na.rm = TRUE),
            sd      = sd(LMCD, na.rm = TRUE)
          ) %>%
          mutate(across(c(media, sd), ~round(.x, 2)))
        res_lmcd
## # A tibble: 2 × 4
##   sexoN      n media    sd
##   <fct>  <int> <dbl> <dbl>
## 1 Hombre    35  151. 10.2 
## 2 Mujer     25  131.  7.56
# Para resumir por sexo la información de Circunferencia media de clavicula derecha
        
      res_C12CD <- HombroS %>%
          group_by(sexoN) %>%
          summarise(
            n       = sum(!is.na(C12CD)),
            media   = mean(C12CD, na.rm = TRUE),
            sd      = sd(C12CD, na.rm = TRUE)
          ) %>%
          mutate(across(c(media, sd), ~round(.x, 2)))
        res_C12CD
## # A tibble: 2 × 4
##   sexoN      n media    sd
##   <fct>  <int> <dbl> <dbl>
## 1 Hombre    35  35.8  2.34
## 2 Mujer     25  30.3  2.86
          ## Gráfica comparativa
        ggplot(HombroS, aes(x = LMCD, fill = sexoN)) +
          geom_density(alpha = 0.5) +
          labs(
            title = "Gráfica 1. Longitud maxima clavicula derecha por sexo",
            x = "Longitud clavicula derecha por sexo (mm)",
            y = "Densidad"
          ) +
          theme_minimal()

        ## Gráfica comparativa
        ggplot(HombroS, aes(x = LMCD, fill = sexoN)) +
          geom_density(alpha = 0.5) +
          labs(
            title = "Gráfica 1. Longitud maxima clavicula derecha por sexo",
            x = "Longitud clavicula derecha por sexo (mm)",
            y = "Densidad"
          ) +
          theme_minimal()

        ggplot(HombroS, aes(x = C12CD, fill = sexoN)) +
          geom_density(alpha = 0.5) +
          labs(
            title = "Gráfica 2. Circunferencia en punto medio de la clavicula derecha",
            x = "Circunferencia en punto medio de la clavicula derecha (mm)",
            y = "Densidad"
          ) +
          theme_minimal()

        # 1. Comparaciones por sexo entre las variables
        ## Realizaremos la prueba t para comparar las medias
        t.test(LMCD ~ sexoN, data = HombroS, var.equal = TRUE)
## 
##  Two Sample t-test
## 
## data:  LMCD by sexoN
## t = 8.2061, df = 58, p-value = 2.767e-11
## alternative hypothesis: true difference in means between group Hombre and group Mujer is not equal to 0
## 95 percent confidence interval:
##  14.91249 24.53489
## sample estimates:
## mean in group Hombre  mean in group Mujer 
##             151.0263             131.3026
        t.test(LMCD ~ sexoN, data = HombroS, var.equal = FALSE)
## 
##  Welch Two Sample t-test
## 
## data:  LMCD by sexoN
## t = 8.6158, df = 57.876, p-value = 5.838e-12
## alternative hypothesis: true difference in means between group Hombre and group Mujer is not equal to 0
## 95 percent confidence interval:
##  15.14104 24.30633
## sample estimates:
## mean in group Hombre  mean in group Mujer 
##             151.0263             131.3026
        t.test(C12CD ~ sexoN, data = HombroS, var.equal = TRUE)
## 
##  Two Sample t-test
## 
## data:  C12CD by sexoN
## t = 8.1156, df = 58, p-value = 3.922e-11
## alternative hypothesis: true difference in means between group Hombre and group Mujer is not equal to 0
## 95 percent confidence interval:
##  4.112868 6.806030
## sample estimates:
## mean in group Hombre  mean in group Mujer 
##             35.77151             30.31206
        t.test(C12CD ~ sexoN, data = HombroS, var.equal = FALSE)
## 
##  Welch Two Sample t-test
## 
## data:  C12CD by sexoN
## t = 7.8461, df = 45.117, p-value = 5.68e-10
## alternative hypothesis: true difference in means between group Hombre and group Mujer is not equal to 0
## 95 percent confidence interval:
##  4.058095 6.860803
## sample estimates:
## mean in group Hombre  mean in group Mujer 
##             35.77151             30.31206
# los valores son parametricos por lo que no es necesario hacer la prueba U
        
## 2. Construir una función discriminante para LMCD 
## Ajustar Discriminante Lineal
        # Eliminar NAs de forma explícita
        HombroS <- na.omit(Hombro[, c("sexoN", "LMCD")])
        # Ajustar el modelo con la base depurada
        ## El modelo discriminante es D=a*LMCD+b
        lda1 <- lda(sexoN ~ LMCD, data = HombroS)
        a <- coef(lda1) ## El factor que multiplica a LMCD
        pred0 <- predict(lda1,
                         newdata = data.frame(LMCD = 0))
        b <- pred0$x    # valor de D cuando LMCD=0 es b
        pred <- predict(lda1) ## Predicción de sexo para todos los valores de 
        # medias de la función discriminante por grupo
        centroide_H <- mean(pred$x[HombroS$sexoN == "Hombre"])
        centroide_M <- mean(pred$x[HombroS$sexoN == "Mujer"])
        # Punto de corte (promedio de centroides, priors iguales)
        cutoff <- mean(c(centroide_H, centroide_M))
        
        ## El modelo discriminante es
        cat("Función discriminante: D(x) = ", round(a, 4), " * LMCD + ", round(b, 4), "\n")
## Función discriminante: D(x) =  0.1089  * LMCD +  -15.5587
        cat("Punto de corte=", round(cutoff, 4), "Si D>",round(cutoff, 4), "es Hombre")
## Punto de corte= -0.1791 Si D> -0.1791 es Hombre
 ## Función discriminante: D(x) =  0.1089  * LMCD +  -15.5587 
## Punto de corte= -0.1791 Si D> -0.1791 es Hombre
        # Tabla cruzada
        tabla_clas <- table(Observado = HombroS$sexoN,
                            Predicho  = pred$class)
        tabla_clas
##          Predicho
## Observado Hombre Mujer
##    Hombre     32     3
##    Mujer       3    22
        prop_clas <- sum(diag(tabla_clas)) / sum(tabla_clas)*100
        cat("El porcentaje de clasificación correcta es ",round(prop_clas,1),"%")
## El porcentaje de clasificación correcta es  90 %
##  El porcentaje de clasificación correcta es  90 %      

## Ejemplo de aplicación
        
        # Valores del modelo obtenidos
        a <- 0.1089       # coeficiente de LMCD
        b <- -15.5587     # intercepto
        cutoff <- -0.1791 # punto de corte
        
        # Valor dado
        LMCD_nuevo <- 130
        
        # Calcular la función discriminante
        D_x <- a * LMCD_nuevo + b
        
        # Mostrar el valor calculado
        cat("El valor discriminante para LMCD=130 es:", round(D_x, 4), "\n")
## El valor discriminante para LMCD=130 es: -1.4017
        # Clasificación según el punto de corte
        if (D_x > cutoff) {
          cat("Clasificación: Hombre\n")
        } else {
          cat("Clasificación: Mujer\n")
        }
## Clasificación: Mujer
## Se clasifica como mujer cuando LMCD= 130

## 3. Construir un modelo discriminante para las dos varables 
         ##Ajustar Disciminante Lineal para dos variables
        # Eliminar NAs de forma explícita
        Hombro_sinNA <- na.omit(Hombro[, c("sexoN", "LMCD","C12CD")])
        # Ajustar el modelo con la base depurada
        ## El modelo discriminante que queremos ajustar es D=a*LMCD+b*C12CD+c
        lda2 <- lda(sexoN ~ LMCD+C12CD, data = Hombro_sinNA) ##Ajustar Disciminante Lineal
        # Obtener los coeficientes a y b
        a1 <- coef(lda2)[1]
        a2 <- coef(lda2)[2]
        lda2
## Call:
## lda(sexoN ~ LMCD + C12CD, data = Hombro_sinNA)
## 
## Prior probabilities of groups:
##    Hombre     Mujer 
## 0.5833333 0.4166667 
## 
## Group means:
##            LMCD    C12CD
## Hombre 151.0263 35.77151
## Mujer  131.3026 30.31206
## 
## Coefficients of linear discriminants:
##              LD1
## LMCD  -0.0727066
## C12CD -0.2559868
        # Predicción de valores mediante modelo
        pred2 <- predict(lda2)
        
        # Matriz de confusión
        table(Real = HombroS$sexoN, Predicho = pred2$class)
##         Predicho
## Real     Hombre Mujer
##   Hombre     34     1
##   Mujer       1    24
        # Porcentaje de acierto
        mean(pred2$class == HombroS$sexoN)*100
## [1] 96.66667
        # valor de D cuando LMCD=0 y C12CD=0 (intercepto)
        b <- predict(lda2,
                     newdata = data.frame(LMCD = 0, C12CD = 0))$x
        b
##        LD1
## 1 18.95782
        centroide_H <- mean(pred2$x[Hombro_sinNA$sexoN == "Hombre"])
        centroide_M <- mean(pred2$x[Hombro_sinNA$sexoN == "Mujer"])
        cutoff <- mean(c(centroide_H, centroide_M))
        cutoff
## [1] 0.2359658
        cat("Función discriminante: D(x) = ", round(a1, 4), " * LMHD + ", round(a2, 4),"*ABHD +",round(b, 4), "\n")
## Función discriminante: D(x) =  -0.0727  * LMHD +  -0.256 *ABHD + 18.9578
        cat("Punto de corte=", round(cutoff, 4), "Si D>",round(cutoff, 4), "es Hombre")
## Punto de corte= 0.236 Si D> 0.236 es Hombre
  ## Función discriminante: D(x) =  -0.0727  * LMHD +  -0.256 *ABHD + 18.9578 
  ## Punto de corte= 0.236 Si D> 0.236 es Hombre
        
        ggplot(Hombro_sinNA, aes(x = LMCD, y = C12CD, color = sexoN)) +
          geom_point(size = 3) +
          theme_minimal() +
          labs(title = "Discriminante lineal: LMCDD vs C12CD")

        a1 <- lda2$scaling["LMCD", 1]
        a2 <- lda2$scaling["C12CD", 1]
        b  <- predict(lda2, newdata = data.frame(LMCD = 0, C12CD = 0))$x - cutoff
        
        # Ecuación de la recta: a1*LMCD + a2*C12CD + b = 0
        # => C12CD = -(a1/a2)*LMCD - b/a2
        
        LD1 <- pred2$x[, 1]
        
        ggplot(data.frame(LD1, sexoN = Hombro_sinNA$sexoN),
               aes(x = LD1, fill = sexoN)) +
          geom_density(alpha = 0.4) +
          geom_vline(xintercept = cutoff, linetype = "dashed") +
          scale_x_continuous(limits = c(-5, 5)) +       # <-- escala de -5 a 5
          theme_minimal() +
          labs(title = "Distribución sobre la función discriminante",
               x = "LD1 (puntuación discriminante)",
               y = "Densidad")

## Ejemplo de aplicación
        # Coeficientes del modelo ya calculado
        a1 <- -0.0727     # coeficiente LMCD
        a2 <- -0.256      # coeficiente C12CD
        c  <- 18.9578     # intercepto
        cutoff <- 0.236   # punto de corte
        
        # Valores nuevos
        LMCD_nuevo  <- 140
        C12CD_nuevo <- 35
        
        # Calcular la función discriminante
        D_x <- a1 * LMCD_nuevo + a2 * C12CD_nuevo + c
        
        # Mostrar resultado
        cat("Valor de D(x) para LMCD=140 y C12CD=35:", round(D_x, 4), "\n")
## Valor de D(x) para LMCD=140 y C12CD=35: -0.1802
        # Clasificación
        if (D_x > cutoff) {
          cat("Clasificación: Hombre\n")
        } else {
          cat("Clasificación: Mujer\n")
        }
## Clasificación: Mujer
## 4. Modelo logistico para calcular % de clasificación correcta      
        ## Omitir datos perdidos
        Hombro_sinNA <- na.omit(Hombro[, c("sexoN", "LMCD","C12CD")])
        # Ajustar modelo logístico binario
        modelo1 <- glm(sexoN ~ LMCD,
                       data = Hombro_sinNA,
                       family = binomial(link = "logit"))
        summary(modelo1)
## 
## Call:
## glm(formula = sexoN ~ LMCD, family = binomial(link = "logit"), 
##     data = Hombro_sinNA)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept) 41.72697   10.79320   3.866 0.000111 ***
## LMCD        -0.29945    0.07717  -3.880 0.000104 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 81.503  on 59  degrees of freedom
## Residual deviance: 32.430  on 58  degrees of freedom
## AIC: 36.43
## 
## Number of Fisher Scoring iterations: 6
        # Probabilidades de ser "Hombre"
        Hombro_sinNA$prob_Hombre2 <- predict(modelo1, type = "response")
        
        # Clasificación usando 0.5 como punto de corte
        Hombro_sinNA$predicho2 <- ifelse(Hombro_sinNA$prob_Hombre2 >= 0.5, "Hombre", "Mujer")
        
        # Matriz de confusión
        table(Real = Hombro_sinNA$sexoN, Predicho2 = Hombro_sinNA$predicho2)
##         Predicho2
## Real     Hombre Mujer
##   Hombre      3    32
##   Mujer      22     3
        # Porcentaje de acierto
        mean(Hombro_sinNA$sexoN == Hombro_sinNA$predicho2) * 100
## [1] 10
        ggplot(Hombro_sinNA, aes(x = prob_Hombre2, fill = sexoN)) +
          geom_density(alpha = 0.45, linewidth = 1) +
          geom_vline(xintercept = 0.5, color = "red", linetype = "dashed", linewidth = 1) +
          scale_fill_manual(values = c("Hombre" = "#1f77b4", "Mujer" = "#ff7f0e")) +
          theme_minimal(base_size = 14) +
          labs(
            title = "Distribución de las probabilidades predichas de ser Hombre",
            subtitle = "Modelo logístico con LMCD y C12CD",
            x = "Probabilidad predicha: P(Hombre)",
            y = "Densidad",
            fill = "Sexo real"
          ) +
          theme(
            plot.title = element_text(face = "bold"),
            legend.position = "top"
          )

        coef(modelo1)
## (Intercept)        LMCD 
##  41.7269684  -0.2994501
        # Ajustar el modelo logístico
        glm_lmcd <- glm(sexoN ~ LMCD,
                        data = Hombro_sinNA,
                        family = binomial(link = "logit"))
        # Coeficientes
        coef_glm_lmcd <- coef(modelo1)
        
        # Ejemplo de aplicación (LMCD hipotético, e.g., 150)
        LMCD_hipotetico_glm <- 150
        logit_ejemplo_glm_lmcd <- coef_glm_lmcd[1] + (coef_glm_lmcd[2] * LMCD_hipotetico_glm)
        prob_ejemplo_glm_lmcd <- exp(logit_ejemplo_glm_lmcd) / (1 + exp(logit_ejemplo_glm_lmcd))
        clasificacion_glm_lmcd <- ifelse(prob_ejemplo_glm_lmcd >= 0.5, "Hombre", "Mujer")
        cat(paste0("**Ejemplo de Aplicación** (LMCD=", LMCD_hipotetico_glm, " mm):\n"))
## **Ejemplo de Aplicación** (LMCD=150 mm):
        ggplot(Hombro_sinNA, aes(x = prob_Hombre2, fill = sexoN)) +
          geom_density(alpha = 0.4) +
          geom_vline(xintercept = 0.5, linetype = "dashed", color = "black") +
          labs(title = "Probabilidades Predichas de ser Hombre (LMCD)",
               x = "P(Hombre)",
               y = "Densidad") +
          theme_minimal()       

## 5. Ajustar modelo logistico, calcular el % de clasificación correcta usando clasificación % correcta usando variables LMCD Y C12CD
        
        # Ajustar modelo logístico binario
        modelo2 <- glm(sexoN ~ LMCD + C12CD,
                       data = Hombro_sinNA,
                       family = binomial(link = "logit"))
        summary(modelo2)
## 
## Call:
## glm(formula = sexoN ~ LMCD + C12CD, family = binomial(link = "logit"), 
##     data = Hombro_sinNA)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept)  69.0885    22.9591   3.009  0.00262 **
## LMCD         -0.3067     0.1117  -2.747  0.00602 **
## C12CD        -0.8022     0.3405  -2.356  0.01847 * 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 81.503  on 59  degrees of freedom
## Residual deviance: 18.731  on 57  degrees of freedom
## AIC: 24.731
## 
## Number of Fisher Scoring iterations: 8
        # Probabilidades de ser "Hombre"
        Hombro_sinNA$prob_Hombre <- predict(modelo2, type = "response")
        
        # Clasificación usando 0.5 como punto de corte
        Hombro_sinNA$predicho <- ifelse(Hombro_sinNA$prob_Hombre >= 0.5, "Hombre", "Mujer")
        
        # Matriz de confusión
        table(Real = Hombro_sinNA$sexoN, Predicho = Hombro_sinNA$predicho)
##         Predicho
## Real     Hombre Mujer
##   Hombre      1    34
##   Mujer      24     1
        # Porcentaje de acierto
        mean(Hombro_sinNA$sexoN == Hombro_sinNA$predicho) * 100
## [1] 3.333333
        ## Gráfica de probabilidades predichas
        
        ggplot(Hombro_sinNA, aes(x = prob_Hombre, fill = sexoN)) +
          geom_density(alpha = 0.4) +
          geom_vline(xintercept = 0.5, linetype = "dashed") +
          theme_minimal() +
          labs(title = "Probabilidades predichas de ser Hombre",
               x = "P(Hombre)", y = "Densidad")

        coef(modelo2)
## (Intercept)        LMCD       C12CD 
##  69.0884686  -0.3067252  -0.8022468
        cat("Ecuación logística:\nlogit(p) = ",
            round(coef(modelo2)[1], 4), " + ",
            round(coef(modelo2)[2], 4), "*LMCD + ",
            round(coef(modelo2)[3], 4), "*C12CD\n")
## Ecuación logística:
## logit(p) =  69.0885  +  -0.3067 *LMCD +  -0.8022 *C12CD
        # Ejemplo de aplicación
        # 1. Extraer coeficientes del modelo ya ajustado
        b0 <- coef(modelo2)[1]
        b1 <- coef(modelo2)[2]
        b2 <- coef(modelo2)[3]
        
        # 2. Valores específicos
        LMCD_val <- 160
        C12CD_val <- 30
        
        # 3. Calcular logit y probabilidad
        logit_p <- b0 + b1 * LMCD_val + b2 * C12CD_val
        probabilidad <- exp(logit_p) / (1 + exp(logit_p))
        
        cat("Probabilidad predicha de ser Hombre =", round(probabilidad, 4), "\n")
## Probabilidad predicha de ser Hombre = 0.017
        # 4. Clasificación según punto de corte = 0.5
        clasificacion <- ifelse(probabilidad >= 0.5, "Hombre", "Mujer")
        cat("Clasificación predicha =", clasificacion, "\n\n")
## Clasificación predicha = Mujer
        # 5. Porcentaje de clasificación correcta del modelo completo
        Hombro_sinNA$prob_Hombre <- predict(modelo2, type = "response")
        Hombro_sinNA$predicho <- ifelse(Hombro_sinNA$prob_Hombre >= 0.5, "Hombre", "Mujer")
        
        porcentaje_clasificacion <- mean(Hombro_sinNA$sexoN == Hombro_sinNA$predicho) * 100
        
        cat("Porcentaje de clasificación correcta del modelo =", 
            round(porcentaje_clasificacion, 2), "%\n")
## Porcentaje de clasificación correcta del modelo = 3.33 %