library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.1.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(skimr)
library(summarytools)
## Warning in fun(libname, pkgname): couldn't connect to display ":0"
## 
## Attaching package: 'summarytools'
## 
## The following object is masked from 'package:tibble':
## 
##     view
library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## 
## The following object is masked from 'package:dplyr':
## 
##     recode
## 
## The following object is masked from 'package:purrr':
## 
##     some
library(agricolae)
library(dplyr)

A. Exploración de Datos

1. Carga de la base de datos

NOVILLOS <- read.csv("novillos.csv", header = TRUE, sep = ",")

2. Explorar la estructura

Nombres de las variables

names(NOVILLOS)         
## [1] "TRATAMIENTO"  "CORRAL"       "ANIMAL_NUM"   "PESO_INICIAL" "PESO_FINAL"  
## [6] "GANANCIA"

Tipo de variables y estructura

str(NOVILLOS)         
## 'data.frame':    45 obs. of  6 variables:
##  $ TRATAMIENTO : chr  "P15" "P15" "P15" "P15" ...
##  $ CORRAL      : int  1 1 1 1 1 2 2 2 2 2 ...
##  $ ANIMAL_NUM  : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ PESO_INICIAL: int  121 210 200 222 209 315 312 311 309 300 ...
##  $ PESO_FINAL  : int  447 446 445 446 444 432 435 436 432 431 ...
##  $ GANANCIA    : int  326 236 245 224 235 117 123 125 123 131 ...

Primeros registros

head(NOVILLOS)        
##   TRATAMIENTO CORRAL ANIMAL_NUM PESO_INICIAL PESO_FINAL GANANCIA
## 1         P15      1          1          121        447      326
## 2         P15      1          2          210        446      236
## 3         P15      1          3          200        445      245
## 4         P15      1          4          222        446      224
## 5         P15      1          5          209        444      235
## 6         P15      2          6          315        432      117

Resumen estadístico

summary(NOVILLOS)    
##  TRATAMIENTO            CORRAL    ANIMAL_NUM  PESO_INICIAL     PESO_FINAL   
##  Length:45          Min.   :1   Min.   : 1   Min.   :112.0   Min.   :411.0  
##  Class :character   1st Qu.:1   1st Qu.: 4   1st Qu.:200.0   1st Qu.:417.0  
##  Mode  :character   Median :2   Median : 8   Median :221.0   Median :433.0  
##                     Mean   :2   Mean   : 8   Mean   :231.9   Mean   :431.4  
##                     3rd Qu.:3   3rd Qu.:12   3rd Qu.:310.0   3rd Qu.:444.0  
##                     Max.   :3   Max.   :15   Max.   :321.0   Max.   :449.0  
##     GANANCIA    
##  Min.   : 97.0  
##  1st Qu.:123.0  
##  Median :198.0  
##  Mean   :199.5  
##  3rd Qu.:245.0  
##  Max.   :335.0

3. Calcular ganancia de peso promedio por corral y luego resumir por tratamiento

3.1. Calcular la ganancia de peso promedio por corral para cada tratamiento

NOVILLOS_DIETA <- NOVILLOS %>%
  group_by(TRATAMIENTO, CORRAL) %>%
  summarise(GANANCIA_PROMEDIO = mean(GANANCIA, na.rm = TRUE)) %>%
  ungroup() %>%
  mutate(TRATAMIENTO = factor(TRATAMIENTO))
## `summarise()` has grouped output by 'TRATAMIENTO'. You can override using the
## `.groups` argument.
# Visualizar la tabla resultante
print(NOVILLOS_DIETA)
## # A tibble: 9 × 3
##   TRATAMIENTO CORRAL GANANCIA_PROMEDIO
##   <fct>        <int>             <dbl>
## 1 P15              1              253.
## 2 P15              2              124.
## 3 P15              3              256.
## 4 P25              1              291.
## 5 P25              2              124.
## 6 P25              3              234.
## 7 P35              1              212.
## 8 P35              2              125.
## 9 P35              3              176.

3.2. Exploramos al base de datos

str(NOVILLOS_DIETA)
## tibble [9 × 3] (S3: tbl_df/tbl/data.frame)
##  $ TRATAMIENTO      : Factor w/ 3 levels "P15","P25","P35": 1 1 1 2 2 2 3 3 3
##  $ CORRAL           : int [1:9] 1 2 3 1 2 3 1 2 3
##  $ GANANCIA_PROMEDIO: num [1:9] 253 124 256 291 124 ...

3.3. Primeros registros

head(NOVILLOS_DIETA)        
## # A tibble: 6 × 3
##   TRATAMIENTO CORRAL GANANCIA_PROMEDIO
##   <fct>        <int>             <dbl>
## 1 P15              1              253.
## 2 P15              2              124.
## 3 P15              3              256.
## 4 P25              1              291.
## 5 P25              2              124.
## 6 P25              3              234.

4. Obtener medidas descriptivas por tratamiento

4.1. Medidas de resumen

DESCRIPTIVAS <- NOVILLOS_DIETA %>%
  group_by(TRATAMIENTO) %>%
  summarise(
    Media = mean(GANANCIA_PROMEDIO, na.rm = TRUE),
    Mediana = median(GANANCIA_PROMEDIO, na.rm = TRUE),
    Desviacion = sd(GANANCIA_PROMEDIO, na.rm = TRUE),
    Minimo = min(GANANCIA_PROMEDIO, na.rm = TRUE),
    Maximo = max(GANANCIA_PROMEDIO, na.rm = TRUE),
    N = n()
  )
# Mostrar resultados en una tabla
DESCRIPTIVAS
## # A tibble: 3 × 7
##   TRATAMIENTO Media Mediana Desviacion Minimo Maximo     N
##   <fct>       <dbl>   <dbl>      <dbl>  <dbl>  <dbl> <int>
## 1 P15          211.    253.       75.6   124.   256.     3
## 2 P25          216.    234.       84.6   124.   291.     3
## 3 P35          171.    176.       43.9   125.   212.     3

4.2. Visualización de datos

library(ggplot2)

ggplot(NOVILLOS_DIETA, aes(x = TRATAMIENTO, y = GANANCIA_PROMEDIO, fill = TRATAMIENTO)) +
  geom_boxplot(alpha = 0.6) +
  stat_summary(fun = mean, geom = "point", shape = 20, size = 3, color = "black") +
  labs(title = "Ganancia de peso por tratamiento (a nivel de corral)",
       x = "Tratamiento", y = "Ganancia promedio de peso") +
  theme_minimal()

4.3. Conclusiones

El Tratamiento P25 alcanzó la mayor media de ganancia de peso, lo que lo hace el más prometedor en términos productivos, aunque su alta variabilidad entre corrales sugiere diferencias de manejo o respuesta de los animales. El Tratamiento P15 también resultó eficiente, con ganancias promedio similares a P25 pero con menor dispersión, lo que lo convierte en una alternativa más estable y uniforme. El Tratamiento P35 fue el menos favorable, mostrando la ganancia promedio más baja en todos los corrales evaluados.

B. Análisis de Varianza (ANOVA)

5. Hipótesis

_Hipótesis nula (H₀): No existen diferencias significativas en la ganancia de peso promedio entre tratamientos.

H0:μP15=μP25=μP35

_Hipótesis alternativa (H₁): Al menos un tratamiento difiere en la ganancia de peso promedio.

H1:∃ i,j tal que μi ≠ μj

6. Ajuste del modelo ANOVA

Como la unidad experimental es el corral, usaremos la tabla NOVILLOS_DIETA (ganancia promedio por corral):

# Creamos el objeto modelo_dca
modelo_dca <- aov(GANANCIA_PROMEDIO ~ TRATAMIENTO, data = NOVILLOS_DIETA)

# Resumen del modelo
summary(modelo_dca)
##             Df Sum Sq Mean Sq F value Pr(>F)
## TRATAMIENTO  2   3668    1834   0.372  0.704
## Residuals    6  29614    4936

7. Interpretar

Interpretación: El análisis de varianza mostró que el efecto del tratamiento sobre la ganancia de peso a nivel de corral fue no significativo (F = 0,704; p = 0,05). Por lo tanto, no existe evidencia estadísticamente significativa para rechazar la hipótesis nula, lo que indica que no se detectaron diferencias significativas entre los tratamientos evaluados.

C. Verificación de Supuestos

8. Gráficos diagnósticos del modelo

Trabajamos con los residuos y predichos del modelo para realizar las pruebas de los errores.

8.1. Residuos y valores predichos

residuos_dca <- modelo_dca$residuals       # residuos = observado - predicho
predichos_dca <- modelo_dca$fitted.values  # valores predichos
names(modelo_dca$model)
## [1] "GANANCIA_PROMEDIO" "TRATAMIENTO"

8.2. Crear tabla con observados, predichos, residuos y tratamiento

tabla <- data.frame(
  Observado   = modelo_dca$model[[1]],  # primera columna usada en el modelo
  Predichos   = predichos_dca,
  Residual    = residuos_dca,
  Tratamiento = modelo_dca$model[[2]]   # segunda columna usada en el modelo
)

print(tabla)
##   Observado Predichos   Residual Tratamiento
## 1     253.2  211.1333  42.066667         P15
## 2     123.8  211.1333 -87.333333         P15
## 3     256.4  211.1333  45.266667         P15
## 4     290.6  216.2000  74.400000         P25
## 5     124.2  216.2000 -92.000000         P25
## 6     233.8  216.2000  17.600000         P25
## 7     212.2  171.0667  41.133333         P35
## 8     124.8  171.0667 -46.266667         P35
## 9     176.2  171.0667   5.133333         P35

8.3. Gráficos diagnósticos del modelo (residuos vs predichos y Q-Q plot).

Normalidad

Gráfico Q-Q plot
plot(modelo_dca, which = 2)

Interpretación: En este Q-Q plot de residuos se puede observa que la mayoría de los puntos siguen bastante bien la línea diagonal, lo cual indica que los residuos se aproximan a una distribución normal. En los extremos hay ligeras desviaciones. No se observan curvaturas sistemáticas ni grandes desviaciones, lo que respalda que el supuesto de normalidad de los errores se cumple.

Homocedasticidad

Gráfico de residuos vs predichos
plot(modelo_dca, which = 1)

Interpretación: El gráfico de residuos vs valores ajustados del modelo ANOVA muestra que los residuos se distribuyen de manera aleatoria alrededor de la línea horizontal en cero, sin evidenciar un patrón definido. Esto sugiere que el supuesto de homogeneidad de varianzas se cumple de forma razonable. Sin embargo, se identifican algunas observaciones atípicas (outliers) que se alejan del resto de los datos, las cuales podrían influir en los resultados y convendría revisar.

9. Evaluar la normalidad de los residuos

9.1. Prueba de Shapiro-Wilks

H0: SI se cumple el supuesto de Normalidad.

H1: NO se cumple el supuesto de Normalidad.

shapiro.test(modelo_dca$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  modelo_dca$residuals
## W = 0.88492, p-value = 0.1768

Interpretación: La hipótesis nula (H₀) de la prueba Shapiro–Wilk es: “los residuos siguen una distribución normal”. Como el p-value = 0.1768 > 0.05, no se rechaza H₀. Eso significa que los residuos cumplen con el supuesto de normalidad (p > 0.05, Shapiro–Wilk).

10. Homocedasticidad

H0: SI cumple el supuesto de Homocedasticidad.

H1: NO se cumple el supuesto de Homocedasticidad

levene_test <- leveneTest(GANANCIA_PROMEDIO ~ TRATAMIENTO, data = NOVILLOS_DIETA)
levene_test
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  2  0.1718 0.8462
##        6

Interpretación: La hipótesis nula (H₀) de la prueba de Levene es: “las varianzas son iguales entre los grupos”.Como p-value = 0.8462 > 0.05, no se rechaza H₀. Esto significa que se cumple el supuesto de homogeneidad de varianzas requerido para el ANOVA.

D. Comparación de Medias

12. Si resulta pertinente, realice una prueba de comparaciones múltiples para comparar los tratamientos.

summary(modelo_dca)
##             Df Sum Sq Mean Sq F value Pr(>F)
## TRATAMIENTO  2   3668    1834   0.372  0.704
## Residuals    6  29614    4936

Interpretación: El análisis de varianza mostró que no existen diferencias significativas en la ganancia promedio entre los tratamientos evaluados (p > 0.05). En consecuencia, no resulta necesario aplicar pruebas de comparaciones múltiples, dado que no se rechaza la hipótesis nula de igualdad de medias.

E. Conclusiones

13. Conclusión integradora

El análisis de la ganancia de peso vivo de novillos Braford en engorde a corral no mostró diferencias significativas (p > 0,05) entre los tres niveles de inclusión del subproducto fibroso (15 %, 25 % y 35 % en base seca). Esto indica que, dentro del rango evaluado, el aumento en la proporción del subproducto no afectó de manera estadísticamente detectable el desempeño productivo de los animales. Sin embargo, al analizar los datos se observa que las medias de ganancia de peso entre tratamientos presentaron variaciones que, aunque no significativas, podrían atribuirse a factores como: *_Variabilidad individual de los animales dentro de cada corral, que puede enmascarar el efecto de las dietas. _Número limitado de repeticiones, lo que reduce la potencia estadística para detectar diferencias pequeñas pero biológicamente relevantes. _Adaptación de los animales al subproducto, ya que un periodo de acostumbramiento insuficiente o diferencias en la digestibilidad pueden influir en el aprovechamiento de la dieta. _Condiciones ambientales (estrés calórico, manejo del agua o del corral) que afectan el consumo y, en consecuencia, la ganancia de peso. En términos prácticos, los resultados sugieren que es posible incluir hasta un 35 % del subproducto en la dieta sin comprometer la performance animal, lo cual representa una alternativa viable para reducir costos de alimentación en sistemas de engorde a corral.*