# ============================================================
# ANÁLISIS FINAL EN RSTUDIO
# Proyecto: Café Castillo - Finca El Guayabo
# Especialización en Estadística
# Estudiante: Nina María Sánchez Ramírez
# Asesora: Dayana Ibeth Castro Guevara
#
# Archivos:
# 1. Resultados_Cafe_2026_4-1.xlsx
# 2. Resultados_Cafe_2026_micro.xlsx
#
# Propósito:
# Contrastar y complementar los resultados obtenidos en SPSS:
# - Muestreo
# - Descriptivos
# - Comparación antes y después de lluvia
# - Análisis bivariado
# - Correlaciones exploratorias
# - Regresión logística binaria
# - Serie temporal por hora de toma con Micro:bit
# - Gráficos llamativos
# - Interpretaciones, conclusiones y recomendaciones
# ============================================================
# ============================================================
# 1. INSTALACION Y CARGUE DE PAQUETES
# ============================================================
paquetes <- c(
"readxl", "dplyr", "tidyr", "janitor", "ggplot2",
"broom", "openxlsx", "scales"
)
paquetes_no_instalados <- paquetes[!(paquetes %in% installed.packages()[, "Package"])]
if(length(paquetes_no_instalados) > 0){
install.packages(paquetes_no_instalados)
}
library(readxl)
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyr)
library(janitor)
##
## Adjuntando el paquete: 'janitor'
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
library(ggplot2)
library(broom)
library(openxlsx)
library(scales)
# ============================================================
# 2. RUTAS DE LOS ARCHIVOS
# ============================================================
ruta_4en1 <- "C:\\Users\\Nina Sanchez\\Documents\\ACER -LENOVO-NINA 2019-20\\1. USCO\\ESTADISTICA\\2026_Estadistica\\tesis\\Resultados_Cafe_2026_4-1.xlsx"
ruta_micro <- "C:\\Users\\Nina Sanchez\\Documents\\ACER -LENOVO-NINA 2019-20\\1. USCO\\ESTADISTICA\\2026_Estadistica\\tesis\\Resultados_Cafe_2026_micro.xlsx"
# ============================================================
# 3. CREAR CARPETAS DE RESULTADOS
# ============================================================
dir.create("resultados_cafe_rstudio", showWarnings = FALSE)
dir.create("resultados_cafe_rstudio/graficos", showWarnings = FALSE)
dir.create("resultados_cafe_rstudio/tablas", showWarnings = FALSE)
# ============================================================
# 4. CARGAR BASES
# ============================================================
hojas_4en1 <- excel_sheets(ruta_4en1)
hojas_micro <- excel_sheets(ruta_micro)
cat("\n============================================================\n")
##
## ============================================================
cat("HOJAS DETECTADAS\n")
## HOJAS DETECTADAS
cat("============================================================\n")
## ============================================================
cat("\nArchivo 4 en 1:\n")
##
## Archivo 4 en 1:
print(hojas_4en1)
## [1] "4-1"
cat("\nArchivo Micro:bit:\n")
##
## Archivo Micro:bit:
print(hojas_micro)
## [1] "microbit"
hoja_4en1 <- ifelse("4-1" %in% hojas_4en1, "4-1", hojas_4en1[1])
hoja_micro <- ifelse("microbit" %in% hojas_micro, "microbit", hojas_micro[1])
base_4en1 <- read_excel(ruta_4en1, sheet = hoja_4en1) %>%
clean_names()
base_micro <- read_excel(ruta_micro, sheet = hoja_micro) %>%
clean_names()
cat("\n============================================================\n")
##
## ============================================================
cat("NOMBRES DE VARIABLES DESPUÉS DE clean_names()\n")
## NOMBRES DE VARIABLES DESPUÉS DE clean_names()
cat("============================================================\n")
## ============================================================
cat("\nBase 4 en 1:\n")
##
## Base 4 en 1:
print(names(base_4en1))
## [1] "no_planta" "altura_cm" "temp_sin_lluvia" "temp_post_lluvia"
## [5] "p_h_sin_lluvia" "p_h_post_lluvia" "hum_sin_lluvia" "hum_post_lluvia"
## [9] "luz_sin_lluvia" "luz_post_lluvia" "cond_planta" "color_hojas"
## [13] "follaje" "vigor_tallo" "flor" "fruto"
cat("\nBase Micro:bit:\n")
##
## Base Micro:bit:
print(names(base_micro))
## [1] "no" "hora_toma"
## [3] "tiempo_min" "hum_zona_inclinada_zona_baja"
## [5] "hum_zona_alta_poca_inclinacion" "clima"
# ============================================================
# 5. AJUSTE DE NOMBRES
# ============================================================
# clean_names() suele convertir pH en p_h.
# Esta sección estandariza los nombres para evitar errores.
if("p_h_sin_lluvia" %in% names(base_4en1)){
base_4en1 <- base_4en1 %>%
rename(ph_sin_lluvia = p_h_sin_lluvia)
}
if("p_h_post_lluvia" %in% names(base_4en1)){
base_4en1 <- base_4en1 %>%
rename(ph_post_lluvia = p_h_post_lluvia)
}
cat("\n============================================================\n")
##
## ============================================================
cat("NOMBRES AJUSTADOS\n")
## NOMBRES AJUSTADOS
cat("============================================================\n")
## ============================================================
print(names(base_4en1))
## [1] "no_planta" "altura_cm" "temp_sin_lluvia" "temp_post_lluvia"
## [5] "ph_sin_lluvia" "ph_post_lluvia" "hum_sin_lluvia" "hum_post_lluvia"
## [9] "luz_sin_lluvia" "luz_post_lluvia" "cond_planta" "color_hojas"
## [13] "follaje" "vigor_tallo" "flor" "fruto"
print(names(base_micro))
## [1] "no" "hora_toma"
## [3] "tiempo_min" "hum_zona_inclinada_zona_baja"
## [5] "hum_zona_alta_poca_inclinacion" "clima"
# ============================================================
# 6. RECODIFICACIÓN DE VARIABLES
# ============================================================
# Fruto en tres categorías:
# No visible, Visible, Abundante
# Se conserva para gráficos descriptivos.
base_4en1 <- base_4en1 %>%
mutate(
fruto_texto = tolower(trimws(as.character(fruto))),
fruto_3cat = case_when(
fruto_texto %in% c("no visible", "no", "sin fruto", "0") ~ "No visible",
fruto_texto %in% c("visible", "poco") ~ "Visible",
fruto_texto %in% c("abundante") ~ "Abundante",
TRUE ~ NA_character_
),
fruto_3cat = factor(
fruto_3cat,
levels = c("No visible", "Visible", "Abundante")
)
)
# Fruto binario:
# 0 = No visible
# 1 = Visible o Abundante
# Esta variable se usa para regresión logística.
base_4en1 <- base_4en1 %>%
mutate(
fruto_bin = case_when(
fruto_3cat == "No visible" ~ 0,
fruto_3cat %in% c("Visible", "Abundante") ~ 1,
TRUE ~ NA_real_
)
)
# Flor:
# 0 = Ausente
# 1 = Presente
base_4en1 <- base_4en1 %>%
mutate(
flor_texto = tolower(trimws(as.character(flor))),
flor_a = case_when(
flor_texto %in% c("ausente", "no", "0") ~ 0,
flor_texto %in% c("presente", "si", "sí", "1") ~ 1,
TRUE ~ NA_real_
)
)
# Humedad posterior:
# 0 = NOR_normal
# 1 = WET_humectante
base_4en1 <- base_4en1 %>%
mutate(
hum_post_texto = tolower(trimws(as.character(hum_post_lluvia))),
hum_post_a = case_when(
grepl("nor|normal|0", hum_post_texto) ~ 0,
grepl("wet|humectante|humedo|húmedo|1", hum_post_texto) ~ 1,
TRUE ~ NA_real_
)
)
# Vigor del tallo:
# 1 = Medio
# 2 = Bueno
# 3 = Muy bueno
base_4en1 <- base_4en1 %>%
mutate(
vigor_texto = tolower(trimws(as.character(vigor_tallo))),
vigor_tallo_a = case_when(
grepl("medio|1", vigor_texto) ~ 1,
grepl("muy bueno|3", vigor_texto) ~ 3,
grepl("bueno|2", vigor_texto) ~ 2,
TRUE ~ NA_real_
),
vigor_tallo_cat = factor(
vigor_tallo_a,
levels = c(1, 2, 3),
labels = c("Medio", "Bueno", "Muy bueno")
)
)
# Clima Micro:bit:
# 0 = Sin lluvia
# 1 = Con lluvia
base_micro <- base_micro %>%
mutate(
clima_texto = tolower(trimws(as.character(clima))),
clima_a = case_when(
grepl("sin", clima_texto) ~ 0,
grepl("con", clima_texto) ~ 1,
TRUE ~ NA_real_
),
clima_cat = factor(
clima_a,
levels = c(0, 1),
labels = c("Sin lluvia", "Con lluvia")
)
)
# ============================================================
# 7. CONVERSIÓN DE VARIABLES NUMÉRICAS
# ============================================================
variables_numericas_4en1 <- c(
"altura_cm", "temp_sin_lluvia", "temp_post_lluvia",
"ph_sin_lluvia", "ph_post_lluvia",
"fruto_bin", "flor_a", "hum_post_a", "vigor_tallo_a"
)
for(v in variables_numericas_4en1){
if(v %in% names(base_4en1)){
base_4en1[[v]] <- as.numeric(base_4en1[[v]])
}
}
variables_numericas_micro <- c(
"tiempo_min",
"hum_zona_inclinada_zona_baja",
"hum_zona_alta_poca_inclinacion",
"clima_a"
)
for(v in variables_numericas_micro){
if(v %in% names(base_micro)){
base_micro[[v]] <- as.numeric(base_micro[[v]])
}
}
# ============================================================
# 8. LIMPIEZA DE HORA_TOMA PARA SERIE TEMPORAL HORARIA
# ============================================================
# La base contiene Hora_Toma, no semana ni fecha.
# Por tanto, se trabaja serie temporal por hora de toma.
if("hora_toma" %in% names(base_micro)){
base_micro <- base_micro %>%
mutate(
hora_toma_original = as.character(hora_toma),
hora_toma_limpia = tolower(trimws(hora_toma_original)),
hora_toma_limpia = gsub("\\.", "", hora_toma_limpia),
hora_toma_limpia = gsub("a m", "AM", hora_toma_limpia),
hora_toma_limpia = gsub("p m", "PM", hora_toma_limpia),
hora_toma_limpia = gsub("am", "AM", hora_toma_limpia),
hora_toma_limpia = gsub("pm", "PM", hora_toma_limpia),
hora_toma_formato = as.POSIXct(
hora_toma_limpia,
format = "%I:%M %p",
tz = "America/Bogota"
)
)
} else {
base_micro <- base_micro %>%
mutate(
hora_toma_original = NA_character_,
hora_toma_limpia = NA_character_,
hora_toma_formato = as.POSIXct(NA)
)
}
# Eliminar registros vacíos en Micro:bit
base_micro <- base_micro %>%
filter(
!is.na(tiempo_min),
!is.na(hum_zona_inclinada_zona_baja),
!is.na(hum_zona_alta_poca_inclinacion)
)
# ============================================================
# 9. VALIDACIÓN DE BASES
# ============================================================
cat("\n============================================================\n")
##
## ============================================================
cat("VALIDACIÓN GENERAL\n")
## VALIDACIÓN GENERAL
cat("============================================================\n")
## ============================================================
cat("\nBase 4 en 1\n")
##
## Base 4 en 1
cat("Filas:", nrow(base_4en1), "\n")
## Filas: 28
cat("Columnas:", ncol(base_4en1), "\n")
## Columnas: 26
print(colSums(is.na(base_4en1)))
## no_planta altura_cm temp_sin_lluvia temp_post_lluvia
## 0 0 0 0
## ph_sin_lluvia ph_post_lluvia hum_sin_lluvia hum_post_lluvia
## 0 0 0 0
## luz_sin_lluvia luz_post_lluvia cond_planta color_hojas
## 0 0 0 0
## follaje vigor_tallo flor fruto
## 0 0 0 0
## fruto_texto fruto_3cat fruto_bin flor_texto
## 0 0 0 0
## flor_a hum_post_texto hum_post_a vigor_texto
## 0 0 0 0
## vigor_tallo_a vigor_tallo_cat
## 0 0
cat("\nBase Micro:bit\n")
##
## Base Micro:bit
cat("Filas:", nrow(base_micro), "\n")
## Filas: 72
cat("Columnas:", ncol(base_micro), "\n")
## Columnas: 12
print(colSums(is.na(base_micro)))
## no hora_toma
## 0 0
## tiempo_min hum_zona_inclinada_zona_baja
## 0 0
## hum_zona_alta_poca_inclinacion clima
## 0 0
## clima_texto clima_a
## 0 0
## clima_cat hora_toma_original
## 0 0
## hora_toma_limpia hora_toma_formato
## 0 72
cat("\nTabla de control Fruto original vs Fruto binario:\n")
##
## Tabla de control Fruto original vs Fruto binario:
print(table(base_4en1$fruto, base_4en1$fruto_bin, useNA = "ifany"))
##
## 0 1
## Abundante 0 5
## No Visible 17 0
## Visible 0 6
cat("\nFrecuencia fruto en tres categorías:\n")
##
## Frecuencia fruto en tres categorías:
print(tabyl(base_4en1, fruto_3cat))
## fruto_3cat n percent
## No visible 17 0.6071429
## Visible 6 0.2142857
## Abundante 5 0.1785714
cat("\nFrecuencia fruto binario:\n")
##
## Frecuencia fruto binario:
print(tabyl(base_4en1, fruto_bin))
## fruto_bin n percent
## 0 17 0.6071429
## 1 11 0.3928571
# ============================================================
# 10. CONTEXTO Y MUESTREO
# ============================================================
poblacion_lote <- 200
muestra_4en1 <- nrow(base_4en1)
muestra_micro <- nrow(base_micro)
fraccion_muestreo <- muestra_4en1 / poblacion_lote
muestreo_resumen <- data.frame(
componente = c(
"Población aproximada del lote",
"Plantas evaluadas con equipo 4 en 1",
"Registros temporales Micro:bit",
"Fracción de muestreo base 4 en 1"
),
valor = c(
poblacion_lote,
muestra_4en1,
muestra_micro,
round(fraccion_muestreo, 3)
)
)
cat("\n============================================================\n")
##
## ============================================================
cat("CONTEXTO Y MUESTREO\n")
## CONTEXTO Y MUESTREO
cat("============================================================\n")
## ============================================================
print(muestreo_resumen)
## componente valor
## 1 Población aproximada del lote 200.00
## 2 Plantas evaluadas con equipo 4 en 1 28.00
## 3 Registros temporales Micro:bit 72.00
## 4 Fracción de muestreo base 4 en 1 0.14
cat("\nInterpretación:\n")
##
## Interpretación:
cat("El estudio se desarrolla en un lote aproximado de 200 plantas de café variedad Castillo.\n")
## El estudio se desarrolla en un lote aproximado de 200 plantas de café variedad Castillo.
cat("La base 4 en 1 corresponde a 28 plantas evaluadas mediante muestreo no probabilístico por conveniencia.\n")
## La base 4 en 1 corresponde a 28 plantas evaluadas mediante muestreo no probabilístico por conveniencia.
cat("La base Micro:bit corresponde a registros temporales de humedad del suelo, no a plantas individuales.\n")
## La base Micro:bit corresponde a registros temporales de humedad del suelo, no a plantas individuales.
cat("Por esta razón, las dos bases se analizan de forma complementaria y no se fusionan directamente.\n")
## Por esta razón, las dos bases se analizan de forma complementaria y no se fusionan directamente.
# ============================================================
# 11. DESCRIPTIVOS BASE 4 EN 1
# ============================================================
descriptivos_4en1 <- base_4en1 %>%
summarise(
n = n(),
altura_min = min(altura_cm, na.rm = TRUE),
altura_max = max(altura_cm, na.rm = TRUE),
altura_media = mean(altura_cm, na.rm = TRUE),
altura_de = sd(altura_cm, na.rm = TRUE),
temp_sin_min = min(temp_sin_lluvia, na.rm = TRUE),
temp_sin_max = max(temp_sin_lluvia, na.rm = TRUE),
temp_sin_media = mean(temp_sin_lluvia, na.rm = TRUE),
temp_sin_de = sd(temp_sin_lluvia, na.rm = TRUE),
temp_post_min = min(temp_post_lluvia, na.rm = TRUE),
temp_post_max = max(temp_post_lluvia, na.rm = TRUE),
temp_post_media = mean(temp_post_lluvia, na.rm = TRUE),
temp_post_de = sd(temp_post_lluvia, na.rm = TRUE),
ph_sin_min = min(ph_sin_lluvia, na.rm = TRUE),
ph_sin_max = max(ph_sin_lluvia, na.rm = TRUE),
ph_sin_media = mean(ph_sin_lluvia, na.rm = TRUE),
ph_sin_de = sd(ph_sin_lluvia, na.rm = TRUE),
ph_post_min = min(ph_post_lluvia, na.rm = TRUE),
ph_post_max = max(ph_post_lluvia, na.rm = TRUE),
ph_post_media = mean(ph_post_lluvia, na.rm = TRUE),
ph_post_de = sd(ph_post_lluvia, na.rm = TRUE)
)
cat("\n============================================================\n")
##
## ============================================================
cat("DESCRIPTIVOS BASE 4 EN 1\n")
## DESCRIPTIVOS BASE 4 EN 1
cat("============================================================\n")
## ============================================================
print(descriptivos_4en1)
## # A tibble: 1 × 21
## n altura_min altura_max altura_media altura_de temp_sin_min temp_sin_max
## <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 28 115 158 137. 9.81 24 29
## # ℹ 14 more variables: temp_sin_media <dbl>, temp_sin_de <dbl>,
## # temp_post_min <dbl>, temp_post_max <dbl>, temp_post_media <dbl>,
## # temp_post_de <dbl>, ph_sin_min <dbl>, ph_sin_max <dbl>, ph_sin_media <dbl>,
## # ph_sin_de <dbl>, ph_post_min <dbl>, ph_post_max <dbl>, ph_post_media <dbl>,
## # ph_post_de <dbl>
# ============================================================
# 12. FRECUENCIAS AGRONÓMICAS
# ============================================================
frecuencia_fruto_3cat <- base_4en1 %>%
tabyl(fruto_3cat) %>%
adorn_pct_formatting(digits = 1)
frecuencia_fruto <- base_4en1 %>%
tabyl(fruto_bin) %>%
adorn_pct_formatting(digits = 1)
frecuencia_flor <- base_4en1 %>%
tabyl(flor_a) %>%
adorn_pct_formatting(digits = 1)
frecuencia_humedad_post <- base_4en1 %>%
tabyl(hum_post_a) %>%
adorn_pct_formatting(digits = 1)
frecuencia_vigor <- base_4en1 %>%
tabyl(vigor_tallo_cat) %>%
adorn_pct_formatting(digits = 1)
cat("\n============================================================\n")
##
## ============================================================
cat("FRECUENCIAS AGRONÓMICAS\n")
## FRECUENCIAS AGRONÓMICAS
cat("============================================================\n")
## ============================================================
print(frecuencia_fruto_3cat)
## fruto_3cat n percent
## No visible 17 60.7%
## Visible 6 21.4%
## Abundante 5 17.9%
print(frecuencia_fruto)
## fruto_bin n percent
## 0 17 60.7%
## 1 11 39.3%
print(frecuencia_flor)
## flor_a n percent
## 0 25 89.3%
## 1 3 10.7%
print(frecuencia_humedad_post)
## hum_post_a n percent
## 0 8 28.6%
## 1 20 71.4%
print(frecuencia_vigor)
## vigor_tallo_cat n percent
## Medio 4 14.3%
## Bueno 18 64.3%
## Muy bueno 6 21.4%
# ============================================================
# 13. COMPARACIÓN ANTES Y DESPUÉS DE LA LLUVIA
# ============================================================
comparacion_antes_despues <- base_4en1 %>%
summarise(
temp_sin_media = mean(temp_sin_lluvia, na.rm = TRUE),
temp_post_media = mean(temp_post_lluvia, na.rm = TRUE),
diferencia_temp = temp_post_media - temp_sin_media,
ph_sin_media = mean(ph_sin_lluvia, na.rm = TRUE),
ph_post_media = mean(ph_post_lluvia, na.rm = TRUE),
diferencia_ph = ph_post_media - ph_sin_media
)
prueba_temp_pareada <- t.test(
base_4en1$temp_sin_lluvia,
base_4en1$temp_post_lluvia,
paired = TRUE
)
prueba_ph_pareada <- t.test(
base_4en1$ph_sin_lluvia,
base_4en1$ph_post_lluvia,
paired = TRUE
)
cat("\n============================================================\n")
##
## ============================================================
cat("ANTES VS DESPUÉS DE LA LLUVIA\n")
## ANTES VS DESPUÉS DE LA LLUVIA
cat("============================================================\n")
## ============================================================
print(comparacion_antes_despues)
## # A tibble: 1 × 6
## temp_sin_media temp_post_media diferencia_temp ph_sin_media ph_post_media
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 26.2 20.2 -5.96 6.41 5.04
## # ℹ 1 more variable: diferencia_ph <dbl>
print(prueba_temp_pareada)
##
## Paired t-test
##
## data: base_4en1$temp_sin_lluvia and base_4en1$temp_post_lluvia
## t = 21.356, df = 27, p-value < 2.2e-16
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
## 5.391259 6.537313
## sample estimates:
## mean difference
## 5.964286
print(prueba_ph_pareada)
##
## Paired t-test
##
## data: base_4en1$ph_sin_lluvia and base_4en1$ph_post_lluvia
## t = 9.2204, df = 27, p-value = 7.865e-10
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
## 1.069017 1.680983
## sample estimates:
## mean difference
## 1.375
# ============================================================
# 14. ANÁLISIS BIVARIADO CATEGÓRICO
# ============================================================
tabla_flor_fruto <- table(
Fruto = base_4en1$fruto_bin,
Flor = base_4en1$flor_a
)
tabla_hum_fruto <- table(
Fruto = base_4en1$fruto_bin,
Humedad_post = base_4en1$hum_post_a
)
tabla_vigor_fruto <- table(
Fruto = base_4en1$fruto_bin,
Vigor = base_4en1$vigor_tallo_a
)
chi_flor <- suppressWarnings(chisq.test(tabla_flor_fruto))
chi_hum <- suppressWarnings(chisq.test(tabla_hum_fruto))
chi_vigor <- suppressWarnings(chisq.test(tabla_vigor_fruto))
fisher_flor <- fisher.test(tabla_flor_fruto)
fisher_hum <- fisher.test(tabla_hum_fruto)
resumen_chi <- data.frame(
relacion = c(
"Fruto visible x Flor",
"Fruto visible x Humedad posterior",
"Fruto visible x Vigor del tallo"
),
chi_cuadrado = c(
as.numeric(chi_flor$statistic),
as.numeric(chi_hum$statistic),
as.numeric(chi_vigor$statistic)
),
gl = c(
as.numeric(chi_flor$parameter),
as.numeric(chi_hum$parameter),
as.numeric(chi_vigor$parameter)
),
p_chi = c(
chi_flor$p.value,
chi_hum$p.value,
chi_vigor$p.value
),
p_fisher = c(
fisher_flor$p.value,
fisher_hum$p.value,
NA
)
)
cat("\n============================================================\n")
##
## ============================================================
cat("ANÁLISIS BIVARIADO CATEGÓRICO\n")
## ANÁLISIS BIVARIADO CATEGÓRICO
cat("============================================================\n")
## ============================================================
print(tabla_flor_fruto)
## Flor
## Fruto 0 1
## 0 14 3
## 1 11 0
print(tabla_hum_fruto)
## Humedad_post
## Fruto 0 1
## 0 8 9
## 1 0 11
print(tabla_vigor_fruto)
## Vigor
## Fruto 1 2 3
## 0 4 10 3
## 1 0 8 3
print(resumen_chi)
## relacion chi_cuadrado gl p_chi p_fisher
## 1 Fruto visible x Flor 0.720713 1 0.39591013 0.257936508
## 2 Fruto visible x Humedad posterior 5.124599 1 0.02358902 0.009679531
## 3 Fruto visible x Vigor del tallo 3.077837 2 0.21461306 NA
# ============================================================
# 15. ANÁLISIS BIVARIADO CONTINUO
# ============================================================
analisis_t <- function(variable){
grupo0 <- base_4en1 %>%
filter(fruto_bin == 0) %>%
pull(variable)
grupo1 <- base_4en1 %>%
filter(fruto_bin == 1) %>%
pull(variable)
prueba <- t.test(grupo0, grupo1, var.equal = TRUE)
n0 <- length(na.omit(grupo0))
n1 <- length(na.omit(grupo1))
media0 <- mean(grupo0, na.rm = TRUE)
media1 <- mean(grupo1, na.rm = TRUE)
sd0 <- sd(grupo0, na.rm = TRUE)
sd1 <- sd(grupo1, na.rm = TRUE)
sd_pooled <- sqrt(((n0 - 1) * sd0^2 + (n1 - 1) * sd1^2) / (n0 + n1 - 2))
d_cohen <- (media0 - media1) / sd_pooled
data.frame(
variable = variable,
n_sin_fruto = n0,
n_con_fruto = n1,
media_sin_fruto = media0,
media_con_fruto = media1,
t = as.numeric(prueba$statistic),
gl = as.numeric(prueba$parameter),
p_valor = prueba$p.value,
d_cohen = d_cohen
)
}
resumen_t <- bind_rows(
analisis_t("altura_cm"),
analisis_t("temp_post_lluvia"),
analisis_t("ph_post_lluvia"),
analisis_t("ph_sin_lluvia"),
analisis_t("temp_sin_lluvia")
)
cat("\n============================================================\n")
##
## ============================================================
cat("ANÁLISIS BIVARIADO CONTINUO\n")
## ANÁLISIS BIVARIADO CONTINUO
cat("============================================================\n")
## ============================================================
print(resumen_t)
## variable n_sin_fruto n_con_fruto media_sin_fruto media_con_fruto
## 1 altura_cm 17 11 136.117647 138.636364
## 2 temp_post_lluvia 17 11 20.176471 20.363636
## 3 ph_post_lluvia 17 11 5.205882 4.772727
## 4 ph_sin_lluvia 17 11 6.352941 6.500000
## 5 temp_sin_lluvia 17 11 26.411765 25.909091
## t gl p_valor d_cohen
## 1 -0.6564490 26 0.51730361 -0.2540149
## 2 -0.8213853 26 0.41889524 -0.3178375
## 3 2.6296910 26 0.01416553 1.0175668
## 4 -0.7386711 26 0.46672303 -0.2858310
## 5 1.0098236 26 0.32188587 0.3907542
# ============================================================
# 16. CORRELACIONES EXPLORATORIAS CON FRUTO
# ============================================================
variables_cor <- c(
"altura_cm", "temp_post_lluvia", "ph_post_lluvia",
"ph_sin_lluvia", "temp_sin_lluvia", "vigor_tallo_a"
)
correlaciones_fruto <- lapply(variables_cor, function(v){
datos_temp <- base_4en1 %>%
select(fruto_bin, all_of(v)) %>%
filter(!is.na(fruto_bin), !is.na(.data[[v]]))
pearson <- cor.test(datos_temp$fruto_bin, datos_temp[[v]], method = "pearson")
spearman <- suppressWarnings(cor.test(datos_temp$fruto_bin, datos_temp[[v]], method = "spearman"))
data.frame(
variable = v,
pearson_r = as.numeric(pearson$estimate),
pearson_p = pearson$p.value,
spearman_rho = as.numeric(spearman$estimate),
spearman_p = spearman$p.value
)
}) %>%
bind_rows()
cat("\n============================================================\n")
##
## ============================================================
cat("CORRELACIONES EXPLORATORIAS CON FRUTO\n")
## CORRELACIONES EXPLORATORIAS CON FRUTO
cat("============================================================\n")
## ============================================================
print(correlaciones_fruto)
## variable pearson_r pearson_p spearman_rho spearman_p
## 1 altura_cm 0.1276864 0.51730361 0.1042943 0.59739061
## 2 temp_post_lluvia 0.1590367 0.41889524 0.1900529 0.33270366
## 3 ph_post_lluvia -0.4583592 0.01416553 -0.4537006 0.01530975
## 4 ph_sin_lluvia 0.1433688 0.46672303 0.2231550 0.25368045
## 5 temp_sin_lluvia -0.1942696 0.32188587 -0.1721601 0.38101985
## 6 vigor_tallo_a 0.2729080 0.15999391 0.2662633 0.17082128
# ============================================================
# 17. MODELO LOGÍSTICO SIMPLE
# ============================================================
modelo_simple <- glm(
fruto_bin ~ ph_post_lluvia,
data = base_4en1,
family = binomial
)
coef_simple <- tidy(modelo_simple) %>%
mutate(
odds_ratio = exp(estimate),
ic_inf = exp(estimate - 1.96 * std.error),
ic_sup = exp(estimate + 1.96 * std.error)
)
b0_simple <- coef(modelo_simple)[1]
b1_simple <- coef(modelo_simple)[2]
cat("\n============================================================\n")
##
## ============================================================
cat("MODELO LOGÍSTICO SIMPLE\n")
## MODELO LOGÍSTICO SIMPLE
cat("============================================================\n")
## ============================================================
print(summary(modelo_simple))
##
## Call:
## glm(formula = fruto_bin ~ ph_post_lluvia, family = binomial,
## data = base_4en1)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 14.693 7.367 1.995 0.0461 *
## ph_post_lluvia -3.042 1.489 -2.042 0.0411 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 37.521 on 27 degrees of freedom
## Residual deviance: 30.399 on 26 degrees of freedom
## AIC: 34.399
##
## Number of Fisher Scoring iterations: 5
print(coef_simple)
## # A tibble: 2 × 8
## term estimate std.error statistic p.value odds_ratio ic_inf ic_sup
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 14.7 7.37 1.99 0.0461 2.41e+6 1.29 4.49e+12
## 2 ph_post_lluv… -3.04 1.49 -2.04 0.0411 4.78e-2 0.00258 8.85e- 1
cat("\nEcuación modelo simple:\n")
##
## Ecuación modelo simple:
cat("logit(p) =", round(b0_simple, 3), "+", round(b1_simple, 3), "*(pH_PostLluvia)\n")
## logit(p) = 14.693 + -3.042 *(pH_PostLluvia)
# ============================================================
# 18. MODELO LOGÍSTICO MÚLTIPLE
# ============================================================
modelo_multiple <- glm(
fruto_bin ~ altura_cm + ph_post_lluvia + temp_post_lluvia,
data = base_4en1,
family = binomial
)
coef_multiple <- tidy(modelo_multiple) %>%
mutate(
odds_ratio = exp(estimate),
ic_inf = exp(estimate - 1.96 * std.error),
ic_sup = exp(estimate + 1.96 * std.error)
)
b_multiple <- coef(modelo_multiple)
cat("\n============================================================\n")
##
## ============================================================
cat("MODELO LOGÍSTICO MÚLTIPLE\n")
## MODELO LOGÍSTICO MÚLTIPLE
cat("============================================================\n")
## ============================================================
print(summary(modelo_multiple))
##
## Call:
## glm(formula = fruto_bin ~ altura_cm + ph_post_lluvia + temp_post_lluvia,
## family = binomial, data = base_4en1)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.27735 20.28724 0.112 0.911
## altura_cm 0.02325 0.05048 0.461 0.645
## ph_post_lluvia -3.01992 1.54747 -1.952 0.051 .
## temp_post_lluvia 0.44787 0.77443 0.578 0.563
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 37.521 on 27 degrees of freedom
## Residual deviance: 29.950 on 24 degrees of freedom
## AIC: 37.95
##
## Number of Fisher Scoring iterations: 5
print(coef_multiple)
## # A tibble: 4 × 8
## term estimate std.error statistic p.value odds_ratio ic_inf ic_sup
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 2.28 20.3 0.112 0.911 9.75 5.25e-17 1.81e18
## 2 altura_cm 0.0233 0.0505 0.461 0.645 1.02 9.27e- 1 1.13e 0
## 3 ph_post_lluv… -3.02 1.55 -1.95 0.0510 0.0488 2.35e- 3 1.01e 0
## 4 temp_post_ll… 0.448 0.774 0.578 0.563 1.56 3.43e- 1 7.14e 0
cat("\nEcuación modelo múltiple:\n")
##
## Ecuación modelo múltiple:
cat(
"logit(p) =",
round(b_multiple[1], 3), "+",
round(b_multiple["altura_cm"], 3), "*(Altura_cm) +",
round(b_multiple["ph_post_lluvia"], 3), "*(pH_PostLluvia) +",
round(b_multiple["temp_post_lluvia"], 3), "*(Temp_PostLluvia)\n"
)
## logit(p) = 2.277 + 0.023 *(Altura_cm) + -3.02 *(pH_PostLluvia) + 0.448 *(Temp_PostLluvia)
# ============================================================
# 19. PSEUDO R2
# ============================================================
pseudo_r2 <- function(modelo){
ll_modelo <- as.numeric(logLik(modelo))
modelo_nulo <- update(modelo, . ~ 1)
ll_nulo <- as.numeric(logLik(modelo_nulo))
n <- nobs(modelo)
r2_cox_snell <- 1 - exp((2 / n) * (ll_nulo - ll_modelo))
r2_nagelkerke <- r2_cox_snell / (1 - exp((2 / n) * ll_nulo))
data.frame(
r2_cox_snell = r2_cox_snell,
r2_nagelkerke = r2_nagelkerke
)
}
r2_simple <- pseudo_r2(modelo_simple)
r2_multiple <- pseudo_r2(modelo_multiple)
# ============================================================
# 20. MATRIZ DE CLASIFICACIÓN
# ============================================================
clasificacion_modelo <- function(modelo, nombre_modelo){
datos_modelo <- model.frame(modelo)
observado <- datos_modelo[[1]]
probabilidad <- predict(modelo, type = "response")
predicho <- ifelse(probabilidad >= 0.5, 1, 0)
matriz <- table(
Observado = factor(observado, levels = c(0, 1)),
Predicho = factor(predicho, levels = c(0, 1))
)
tn <- matriz["0", "0"]
fp <- matriz["0", "1"]
fn <- matriz["1", "0"]
tp <- matriz["1", "1"]
exactitud <- (tp + tn) / sum(matriz)
sensibilidad <- tp / (tp + fn)
especificidad <- tn / (tn + fp)
resumen <- data.frame(
modelo = nombre_modelo,
exactitud = exactitud,
sensibilidad = sensibilidad,
especificidad = especificidad
)
return(list(
matriz = matriz,
resumen = resumen
))
}
clas_simple <- clasificacion_modelo(modelo_simple, "Simple: pH_PostLluvia")
clas_multiple <- clasificacion_modelo(modelo_multiple, "Múltiple: altura + pH + temperatura")
# ============================================================
# 21. COMPARACIÓN DE MODELOS
# ============================================================
comparacion_modelos <- data.frame(
modelo = c(
"Simple: pH_PostLluvia",
"Múltiple: Altura_cm + pH_PostLluvia + Temp_PostLluvia"
),
menos_2ll = c(
-2 * as.numeric(logLik(modelo_simple)),
-2 * as.numeric(logLik(modelo_multiple))
),
parametros = c(
length(coef(modelo_simple)),
length(coef(modelo_multiple))
),
aic = c(
AIC(modelo_simple),
AIC(modelo_multiple)
),
r2_nagelkerke = c(
r2_simple$r2_nagelkerke,
r2_multiple$r2_nagelkerke
),
exactitud = c(
clas_simple$resumen$exactitud,
clas_multiple$resumen$exactitud
),
sensibilidad = c(
clas_simple$resumen$sensibilidad,
clas_multiple$resumen$sensibilidad
),
especificidad = c(
clas_simple$resumen$especificidad,
clas_multiple$resumen$especificidad
)
)
cat("\n============================================================\n")
##
## ============================================================
cat("COMPARACIÓN DE MODELOS\n")
## COMPARACIÓN DE MODELOS
cat("============================================================\n")
## ============================================================
print(comparacion_modelos)
## modelo menos_2ll parametros
## 1 Simple: pH_PostLluvia 30.39931 2
## 2 Múltiple: Altura_cm + pH_PostLluvia + Temp_PostLluvia 29.94969 4
## aic r2_nagelkerke exactitud sensibilidad especificidad
## 1 34.39931 0.3042200 0.6785714 0.3636364 0.8823529
## 2 37.94969 0.3209541 0.6428571 0.3636364 0.8235294
# ============================================================
# 22. PROBABILIDAD ESTIMADA DE FRUTO SEGÚN PH
# ============================================================
rango_ph <- data.frame(
ph_post_lluvia = seq(
min(base_4en1$ph_post_lluvia, na.rm = TRUE),
max(base_4en1$ph_post_lluvia, na.rm = TRUE),
length.out = 100
)
)
rango_ph$prob_fruto <- predict(
modelo_simple,
newdata = rango_ph,
type = "response"
)
# ============================================================
# 23. ANÁLISIS MICRO:BIT COMO SERIE TEMPORAL POR HORA
# ============================================================
descriptivos_micro <- base_micro %>%
summarise(
n = n(),
tiempo_min_min = min(tiempo_min, na.rm = TRUE),
tiempo_min_max = max(tiempo_min, na.rm = TRUE),
tiempo_min_media = mean(tiempo_min, na.rm = TRUE),
tiempo_min_de = sd(tiempo_min, na.rm = TRUE),
zona_baja_min = min(hum_zona_inclinada_zona_baja, na.rm = TRUE),
zona_baja_max = max(hum_zona_inclinada_zona_baja, na.rm = TRUE),
zona_baja_media = mean(hum_zona_inclinada_zona_baja, na.rm = TRUE),
zona_baja_de = sd(hum_zona_inclinada_zona_baja, na.rm = TRUE),
zona_alta_min = min(hum_zona_alta_poca_inclinacion, na.rm = TRUE),
zona_alta_max = max(hum_zona_alta_poca_inclinacion, na.rm = TRUE),
zona_alta_media = mean(hum_zona_alta_poca_inclinacion, na.rm = TRUE),
zona_alta_de = sd(hum_zona_alta_poca_inclinacion, na.rm = TRUE)
)
prueba_micro_baja <- t.test(
hum_zona_inclinada_zona_baja ~ clima_a,
data = base_micro
)
prueba_micro_alta <- t.test(
hum_zona_alta_poca_inclinacion ~ clima_a,
data = base_micro
)
modelo_tiempo_baja <- lm(
hum_zona_inclinada_zona_baja ~ tiempo_min,
data = base_micro
)
modelo_tiempo_alta <- lm(
hum_zona_alta_poca_inclinacion ~ tiempo_min,
data = base_micro
)
cor_zonas <- cor.test(
base_micro$hum_zona_inclinada_zona_baja,
base_micro$hum_zona_alta_poca_inclinacion,
method = "spearman"
)
## Warning in cor.test.default(base_micro$hum_zona_inclinada_zona_baja,
## base_micro$hum_zona_alta_poca_inclinacion, : cannot compute exact p-value with
## ties
cat("\n============================================================\n")
##
## ============================================================
cat("MICRO:BIT: SERIE TEMPORAL POR HORA DE TOMA\n")
## MICRO:BIT: SERIE TEMPORAL POR HORA DE TOMA
cat("============================================================\n")
## ============================================================
print(descriptivos_micro)
## # A tibble: 1 × 13
## n tiempo_min_min tiempo_min_max tiempo_min_media tiempo_min_de
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 72 30 2160 1095 628.
## # ℹ 8 more variables: zona_baja_min <dbl>, zona_baja_max <dbl>,
## # zona_baja_media <dbl>, zona_baja_de <dbl>, zona_alta_min <dbl>,
## # zona_alta_max <dbl>, zona_alta_media <dbl>, zona_alta_de <dbl>
print(prueba_micro_baja)
##
## Welch Two Sample t-test
##
## data: hum_zona_inclinada_zona_baja by clima_a
## t = 3.7446, df = 61.556, p-value = 4e-04
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
## 3.142521 10.341831
## sample estimates:
## mean in group 0 mean in group 1
## 658.1967 651.4545
print(prueba_micro_alta)
##
## Welch Two Sample t-test
##
## data: hum_zona_alta_poca_inclinacion by clima_a
## t = 3.3836, df = 60.106, p-value = 0.001264
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
## 9.835882 38.280362
## sample estimates:
## mean in group 0 mean in group 1
## 678.9672 654.9091
print(summary(modelo_tiempo_baja))
##
## Call:
## lm(formula = hum_zona_inclinada_zona_baja ~ tiempo_min, data = base_micro)
##
## Residuals:
## Min 1Q Median 3Q Max
## -14.353 -7.614 -1.971 4.918 21.248
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 671.746479 2.411223 278.592 < 2e-16 ***
## tiempo_min -0.013315 0.001914 -6.958 1.49e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 10.12 on 70 degrees of freedom
## Multiple R-squared: 0.4089, Adjusted R-squared: 0.4004
## F-statistic: 48.42 on 1 and 70 DF, p-value: 1.489e-09
print(summary(modelo_tiempo_alta))
##
## Call:
## lm(formula = hum_zona_alta_poca_inclinacion ~ tiempo_min, data = base_micro)
##
## Residuals:
## Min 1Q Median 3Q Max
## -113.42 -24.88 -15.22 23.42 189.74
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 655.30282 12.10959 54.114 <2e-16 ***
## tiempo_min 0.01826 0.00961 1.899 0.0616 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 50.84 on 70 degrees of freedom
## Multiple R-squared: 0.04902, Adjusted R-squared: 0.03543
## F-statistic: 3.608 on 1 and 70 DF, p-value: 0.06162
print(cor_zonas)
##
## Spearman's rank correlation rho
##
## data: base_micro$hum_zona_inclinada_zona_baja and base_micro$hum_zona_alta_poca_inclinacion
## S = 54975, p-value = 0.3315
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## 0.1160989
cat("\nNota metodológica:\n")
##
## Nota metodológica:
cat("La base Micro:bit tiene Hora_Toma y Tiempo_min, pero no fecha ni semana.\n")
## La base Micro:bit tiene Hora_Toma y Tiempo_min, pero no fecha ni semana.
cat("Por tanto, se analiza una serie temporal por horas del día y por tiempo acumulado,\n")
## Por tanto, se analiza una serie temporal por horas del día y por tiempo acumulado,
cat("no una serie semanal 2026.\n")
## no una serie semanal 2026.
# ============================================================
# 24. GRÁFICOS LLAMATIVOS
# ============================================================
# Paleta de colores
color_verde <- "#2E7D32"
color_naranja <- "#F57C00"
color_azul <- "#1565C0"
color_morado <- "#7B1FA2"
color_rojo <- "#C62828"
color_amarillo <- "#FBC02D"
color_turquesa <- "#00897B"
color_rosado <- "#D81B60"
# Gráfico 1. Fruto en tres categorías
grafico_fruto_3cat <- ggplot(base_4en1, aes(x = fruto_3cat, fill = fruto_3cat)) +
geom_bar(color = "black", width = 0.7) +
geom_text(
stat = "count",
aes(label = after_stat(count)),
vjust = -0.4,
size = 5,
fontface = "bold"
) +
scale_fill_manual(
values = c(
"No visible" = color_rojo,
"Visible" = color_turquesa,
"Abundante" = color_amarillo
)
) +
labs(
title = "Distribución de fruto observado en plantas de café",
subtitle = "Base 4 en 1, finca El Guayabo",
x = "Categoría de fruto",
y = "Número de plantas",
fill = "Fruto"
) +
theme_minimal(base_size = 13)
print(grafico_fruto_3cat)

ggsave(
"resultados_cafe_rstudio/graficos/01_fruto_tres_categorias.png",
plot = grafico_fruto_3cat,
width = 9,
height = 6,
dpi = 300
)
# Gráfico 2. Altura de plantas
grafico_altura <- ggplot(
base_4en1,
aes(x = reorder(as.factor(no_planta), altura_cm), y = altura_cm, fill = fruto_3cat)
) +
geom_col(color = "black") +
coord_flip() +
scale_fill_manual(
values = c(
"No visible" = color_rojo,
"Visible" = color_turquesa,
"Abundante" = color_amarillo
)
) +
labs(
title = "Altura de plantas de café según categoría de fruto",
subtitle = "Cada barra representa una planta evaluada",
x = "Planta",
y = "Altura en cm",
fill = "Fruto"
) +
theme_minimal(base_size = 13)
print(grafico_altura)

ggsave(
"resultados_cafe_rstudio/graficos/02_altura_plantas_fruto.png",
plot = grafico_altura,
width = 10,
height = 8,
dpi = 300
)
# Gráfico 3. Temperatura antes y después
datos_temp_largo <- base_4en1 %>%
select(no_planta, temp_sin_lluvia, temp_post_lluvia) %>%
pivot_longer(
cols = c(temp_sin_lluvia, temp_post_lluvia),
names_to = "momento",
values_to = "temperatura"
) %>%
mutate(
momento = factor(
momento,
levels = c("temp_sin_lluvia", "temp_post_lluvia"),
labels = c("Antes de lluvia", "Después de lluvia")
)
)
grafico_temp <- ggplot(datos_temp_largo, aes(x = momento, y = temperatura, fill = momento)) +
geom_boxplot(color = "black", alpha = 0.85) +
geom_jitter(width = 0.12, color = "#263238", size = 2.5) +
scale_fill_manual(values = c("Antes de lluvia" = color_naranja, "Después de lluvia" = color_azul)) +
labs(
title = "Temperatura antes y después de la lluvia",
subtitle = "Comparación microambiental en 28 plantas",
x = "Momento",
y = "Temperatura en °C",
fill = "Momento"
) +
theme_minimal(base_size = 13)
print(grafico_temp)

ggsave(
"resultados_cafe_rstudio/graficos/03_temperatura_antes_despues.png",
plot = grafico_temp,
width = 9,
height = 6,
dpi = 300
)
# Gráfico 4. pH antes y después
datos_ph_largo <- base_4en1 %>%
select(no_planta, ph_sin_lluvia, ph_post_lluvia) %>%
pivot_longer(
cols = c(ph_sin_lluvia, ph_post_lluvia),
names_to = "momento",
values_to = "ph"
) %>%
mutate(
momento = factor(
momento,
levels = c("ph_sin_lluvia", "ph_post_lluvia"),
labels = c("Antes de lluvia", "Después de lluvia")
)
)
grafico_ph <- ggplot(datos_ph_largo, aes(x = momento, y = ph, fill = momento)) +
geom_boxplot(color = "black", alpha = 0.85) +
geom_jitter(width = 0.12, color = "#263238", size = 2.5) +
scale_fill_manual(values = c("Antes de lluvia" = color_morado, "Después de lluvia" = color_verde)) +
labs(
title = "pH del suelo antes y después de la lluvia",
subtitle = "Desplazamiento del pH posterior al evento de lluvia",
x = "Momento",
y = "pH",
fill = "Momento"
) +
theme_minimal(base_size = 13)
print(grafico_ph)

ggsave(
"resultados_cafe_rstudio/graficos/04_ph_antes_despues.png",
plot = grafico_ph,
width = 9,
height = 6,
dpi = 300
)
# Gráfico 5. pH posterior según fruto en tres categorías
grafico_ph_fruto_3cat <- ggplot(
base_4en1,
aes(x = fruto_3cat, y = ph_post_lluvia, fill = fruto_3cat)
) +
geom_boxplot(color = "black", alpha = 0.85) +
geom_jitter(width = 0.12, color = "#263238", size = 2.5) +
scale_fill_manual(
values = c(
"No visible" = color_rojo,
"Visible" = color_turquesa,
"Abundante" = color_amarillo
)
) +
labs(
title = "pH posterior según categoría de fruto",
subtitle = "No visible, visible y abundante",
x = "Categoría de fruto",
y = "pH posterior a la lluvia",
fill = "Fruto"
) +
theme_minimal(base_size = 13)
print(grafico_ph_fruto_3cat)

ggsave(
"resultados_cafe_rstudio/graficos/05_ph_fruto_tres_categorias.png",
plot = grafico_ph_fruto_3cat,
width = 9,
height = 6,
dpi = 300
)
# Gráfico 6. Curva logística simple
grafico_logistico <- ggplot(base_4en1, aes(x = ph_post_lluvia, y = fruto_bin)) +
geom_point(aes(color = fruto_3cat), size = 3) +
stat_smooth(
method = "glm",
method.args = list(family = "binomial"),
se = TRUE,
color = color_azul,
fill = "#BBDEFB",
linewidth = 1.2
) +
scale_color_manual(
values = c(
"No visible" = color_rojo,
"Visible" = color_turquesa,
"Abundante" = color_amarillo
)
) +
labs(
title = "Modelo logístico simple",
subtitle = "Probabilidad de fruto visible según pH posterior a la lluvia",
x = "pH posterior a la lluvia",
y = "Probabilidad estimada de fruto visible",
color = "Fruto"
) +
theme_minimal(base_size = 13)
print(grafico_logistico)
## `geom_smooth()` using formula = 'y ~ x'

ggsave(
"resultados_cafe_rstudio/graficos/06_modelo_logistico_ph.png",
plot = grafico_logistico,
width = 9,
height = 6,
dpi = 300
)
## `geom_smooth()` using formula = 'y ~ x'
# Gráfico 7. Probabilidad estimada según pH
grafico_prob_ph <- ggplot(rango_ph, aes(x = ph_post_lluvia, y = prob_fruto)) +
geom_line(color = color_rosado, linewidth = 1.4) +
geom_point(color = color_azul, size = 1.8) +
scale_y_continuous(labels = percent_format(accuracy = 1)) +
labs(
title = "Probabilidad estimada de fruto visible",
subtitle = "Estimación exploratoria a partir del pH posterior a la lluvia",
x = "pH posterior a la lluvia",
y = "Probabilidad estimada"
) +
theme_minimal(base_size = 13)
print(grafico_prob_ph)

ggsave(
"resultados_cafe_rstudio/graficos/07_probabilidad_fruto_ph.png",
plot = grafico_prob_ph,
width = 9,
height = 6,
dpi = 300
)
# Gráfico 8. Serie temporal Micro:bit por tiempo acumulado
grafico_micro_tiempo <- ggplot(base_micro, aes(x = tiempo_min)) +
geom_line(
aes(y = hum_zona_inclinada_zona_baja, color = "Zona inclinada baja"),
linewidth = 1.2
) +
geom_line(
aes(y = hum_zona_alta_poca_inclinacion, color = "Zona alta poca inclinación"),
linewidth = 1.2
) +
scale_color_manual(
values = c(
"Zona inclinada baja" = color_naranja,
"Zona alta poca inclinación" = color_azul
)
) +
labs(
title = "Serie temporal de humedad del suelo con Micro:bit",
subtitle = "Seguimiento por tiempo acumulado en minutos",
x = "Tiempo en minutos",
y = "Humedad relativa del sensor",
color = "Zona"
) +
theme_minimal(base_size = 13)
print(grafico_micro_tiempo)

ggsave(
"resultados_cafe_rstudio/graficos/08_microbit_tiempo_min.png",
plot = grafico_micro_tiempo,
width = 10,
height = 6,
dpi = 300
)
# Gráfico 9. Serie temporal por hora de toma
if(sum(!is.na(base_micro$hora_toma_formato)) > 0){
grafico_micro_hora <- ggplot(base_micro, aes(x = hora_toma_formato)) +
geom_line(
aes(y = hum_zona_inclinada_zona_baja, color = "Zona inclinada baja"),
linewidth = 1.2
) +
geom_line(
aes(y = hum_zona_alta_poca_inclinacion, color = "Zona alta poca inclinación"),
linewidth = 1.2
) +
geom_point(
aes(y = hum_zona_inclinada_zona_baja),
color = color_naranja,
size = 2
) +
geom_point(
aes(y = hum_zona_alta_poca_inclinacion),
color = color_azul,
size = 2
) +
scale_color_manual(
values = c(
"Zona inclinada baja" = color_naranja,
"Zona alta poca inclinación" = color_azul
)
) +
labs(
title = "Humedad del suelo según hora de toma",
subtitle = "Serie horaria, no semanal",
x = "Hora de toma",
y = "Humedad relativa del sensor",
color = "Zona"
) +
theme_minimal(base_size = 13)
print(grafico_micro_hora)
ggsave(
"resultados_cafe_rstudio/graficos/09_microbit_hora_toma.png",
plot = grafico_micro_hora,
width = 10,
height = 6,
dpi = 300
)
}
# Gráfico 10. Humedad zona alta según clima
grafico_micro_clima <- ggplot(
base_micro,
aes(x = clima_cat, y = hum_zona_alta_poca_inclinacion, fill = clima_cat)
) +
geom_boxplot(color = "black", alpha = 0.85) +
geom_jitter(width = 0.12, color = "#263238", size = 2.4) +
scale_fill_manual(values = c("Sin lluvia" = color_verde, "Con lluvia" = color_azul)) +
labs(
title = "Humedad en zona alta según condición climática",
subtitle = "Lecturas relativas del sensor Micro:bit",
x = "Condición climática",
y = "Humedad relativa del sensor",
fill = "Clima"
) +
theme_minimal(base_size = 13)
print(grafico_micro_clima)

ggsave(
"resultados_cafe_rstudio/graficos/10_microbit_clima_zona_alta.png",
plot = grafico_micro_clima,
width = 9,
height = 6,
dpi = 300
)
# ============================================================
# 25. EXPORTAR RESULTADOS A EXCEL
# ============================================================
wb <- createWorkbook()
addWorksheet(wb, "Muestreo")
writeData(wb, "Muestreo", muestreo_resumen)
addWorksheet(wb, "Descriptivos_4en1")
writeData(wb, "Descriptivos_4en1", descriptivos_4en1)
addWorksheet(wb, "Frecuencia_fruto_3cat")
writeData(wb, "Frecuencia_fruto_3cat", frecuencia_fruto_3cat)
addWorksheet(wb, "Frecuencia_fruto_bin")
writeData(wb, "Frecuencia_fruto_bin", frecuencia_fruto)
addWorksheet(wb, "Frecuencia_flor")
writeData(wb, "Frecuencia_flor", frecuencia_flor)
addWorksheet(wb, "Frecuencia_humedad")
writeData(wb, "Frecuencia_humedad", frecuencia_humedad_post)
addWorksheet(wb, "Frecuencia_vigor")
writeData(wb, "Frecuencia_vigor", frecuencia_vigor)
addWorksheet(wb, "Antes_despues")
writeData(wb, "Antes_despues", comparacion_antes_despues)
addWorksheet(wb, "Chi_cuadrado")
writeData(wb, "Chi_cuadrado", resumen_chi)
addWorksheet(wb, "Pruebas_T")
writeData(wb, "Pruebas_T", resumen_t)
addWorksheet(wb, "Correlaciones_fruto")
writeData(wb, "Correlaciones_fruto", correlaciones_fruto)
addWorksheet(wb, "Modelo_simple")
writeData(wb, "Modelo_simple", coef_simple)
addWorksheet(wb, "Modelo_multiple")
writeData(wb, "Modelo_multiple", coef_multiple)
addWorksheet(wb, "Comparacion_modelos")
writeData(wb, "Comparacion_modelos", comparacion_modelos)
addWorksheet(wb, "Clasificacion_simple")
writeData(wb, "Clasificacion_simple", as.data.frame.matrix(clas_simple$matriz), rowNames = TRUE)
writeData(wb, "Clasificacion_simple", clas_simple$resumen, startRow = 6)
addWorksheet(wb, "Clasificacion_multiple")
writeData(wb, "Clasificacion_multiple", as.data.frame.matrix(clas_multiple$matriz), rowNames = TRUE)
writeData(wb, "Clasificacion_multiple", clas_multiple$resumen, startRow = 6)
addWorksheet(wb, "Descriptivos_micro")
writeData(wb, "Descriptivos_micro", descriptivos_micro)
addWorksheet(wb, "Probabilidad_ph")
writeData(wb, "Probabilidad_ph", rango_ph)
saveWorkbook(
wb,
"resultados_cafe_rstudio/tablas/Resultados_contraste_RStudio_Cafe.xlsx",
overwrite = TRUE
)
# ============================================================
# 26. INTERPRETACIONES TEXTUALES
# ============================================================
cat("\n============================================================\n")
##
## ============================================================
cat("INTERPRETACIÓN GENERAL\n")
## INTERPRETACIÓN GENERAL
cat("============================================================\n")
## ============================================================
cat("\n1. Contexto:\n")
##
## 1. Contexto:
cat("El estudio caracteriza un lote de café variedad Castillo en la finca El Guayabo.\n")
## El estudio caracteriza un lote de café variedad Castillo en la finca El Guayabo.
cat("La base 4 en 1 trabaja con plantas individuales, mientras que la base Micro:bit trabaja con registros temporales.\n")
## La base 4 en 1 trabaja con plantas individuales, mientras que la base Micro:bit trabaja con registros temporales.
cat("\n2. Muestreo:\n")
##
## 2. Muestreo:
cat("La muestra de 28 plantas corresponde a un muestreo no probabilístico por conveniencia.\n")
## La muestra de 28 plantas corresponde a un muestreo no probabilístico por conveniencia.
cat("La fracción aproximada de muestreo es de ", round(fraccion_muestreo * 100, 1), "% del lote estimado.\n", sep = "")
## La fracción aproximada de muestreo es de 14% del lote estimado.
cat("\n3. Fruto:\n")
##
## 3. Fruto:
cat("La variable Fruto se conserva en tres categorías para la descripción: No visible, Visible y Abundante.\n")
## La variable Fruto se conserva en tres categorías para la descripción: No visible, Visible y Abundante.
cat("Para la regresión logística se recodifica como variable binaria: 0 = No visible y 1 = Visible o Abundante.\n")
## Para la regresión logística se recodifica como variable binaria: 0 = No visible y 1 = Visible o Abundante.
cat("\n4. Contraste con SPSS:\n")
##
## 4. Contraste con SPSS:
cat("El análisis en RStudio permite contrastar los resultados obtenidos previamente en SPSS.\n")
## El análisis en RStudio permite contrastar los resultados obtenidos previamente en SPSS.
cat("Se revisan descriptivos, pruebas Chi-cuadrado, pruebas T, correlaciones, regresión logística, AIC y matriz de clasificación.\n")
## Se revisan descriptivos, pruebas Chi-cuadrado, pruebas T, correlaciones, regresión logística, AIC y matriz de clasificación.
cat("\n5. Predicción exploratoria:\n")
##
## 5. Predicción exploratoria:
cat("La predicción de fruto visible se realiza únicamente con la base por planta.\n")
## La predicción de fruto visible se realiza únicamente con la base por planta.
cat("El modelo logístico simple estima la probabilidad de fruto visible a partir del pH posterior a la lluvia.\n")
## El modelo logístico simple estima la probabilidad de fruto visible a partir del pH posterior a la lluvia.
cat("Esta predicción es exploratoria y no debe interpretarse como sistema predictivo definitivo.\n")
## Esta predicción es exploratoria y no debe interpretarse como sistema predictivo definitivo.
cat("\n6. Serie temporal:\n")
##
## 6. Serie temporal:
cat("La base Micro:bit permite construir una serie temporal por hora de toma y por tiempo acumulado en minutos.\n")
## La base Micro:bit permite construir una serie temporal por hora de toma y por tiempo acumulado en minutos.
cat("No se construye una serie semanal 2026 porque no existe una variable de fecha o semana calendario.\n")
## No se construye una serie semanal 2026 porque no existe una variable de fecha o semana calendario.
cat("\n7. No fusión directa:\n")
##
## 7. No fusión directa:
cat("No se fusionan directamente las bases 4 en 1 y Micro:bit porque tienen unidades de análisis diferentes.\n")
## No se fusionan directamente las bases 4 en 1 y Micro:bit porque tienen unidades de análisis diferentes.
cat("Una base trabaja por planta y la otra por tiempo.\n")
## Una base trabaja por planta y la otra por tiempo.
# ============================================================
# 27. CONCLUSIONES
# ============================================================
cat("\n============================================================\n")
##
## ============================================================
cat("CONCLUSIONES\n")
## CONCLUSIONES
cat("============================================================\n")
## ============================================================
cat("\n1. La base 4 en 1 permitió caracterizar 28 plantas de café variedad Castillo mediante variables microambientales y agronómicas.\n")
##
## 1. La base 4 en 1 permitió caracterizar 28 plantas de café variedad Castillo mediante variables microambientales y agronómicas.
cat("\n2. La comparación antes y después de la lluvia permite reconocer cambios en temperatura, pH y humedad, coherentes con el evento de precipitación.\n")
##
## 2. La comparación antes y después de la lluvia permite reconocer cambios en temperatura, pH y humedad, coherentes con el evento de precipitación.
cat("\n3. La variable Fruto puede analizarse en tres categorías para fines descriptivos y en formato binario para regresión logística.\n")
##
## 3. La variable Fruto puede analizarse en tres categorías para fines descriptivos y en formato binario para regresión logística.
cat("\n4. El pH posterior a la lluvia se mantiene como variable relevante para explicar de forma exploratoria la presencia de fruto visible.\n")
##
## 4. El pH posterior a la lluvia se mantiene como variable relevante para explicar de forma exploratoria la presencia de fruto visible.
cat("\n5. El modelo logístico simple permite estimar probabilidades de presencia de fruto visible, pero su capacidad predictiva debe considerarse limitada por el tamaño de muestra.\n")
##
## 5. El modelo logístico simple permite estimar probabilidades de presencia de fruto visible, pero su capacidad predictiva debe considerarse limitada por el tamaño de muestra.
cat("\n6. La base Micro:bit permite analizar la humedad del suelo como serie temporal por hora de toma y por tiempo acumulado.\n")
##
## 6. La base Micro:bit permite analizar la humedad del suelo como serie temporal por hora de toma y por tiempo acumulado.
cat("\n7. La serie Micro:bit no debe usarse directamente para predecir fruto porque sus registros no están asociados planta por planta.\n")
##
## 7. La serie Micro:bit no debe usarse directamente para predecir fruto porque sus registros no están asociados planta por planta.
cat("\n8. El contraste entre SPSS y RStudio fortalece la consistencia del análisis y permite generar gráficos más claros para presentación.\n")
##
## 8. El contraste entre SPSS y RStudio fortalece la consistencia del análisis y permite generar gráficos más claros para presentación.
# ============================================================
# 28. RECOMENDACIONES
# ============================================================
cat("\n============================================================\n")
##
## ============================================================
cat("RECOMENDACIONES\n")
## RECOMENDACIONES
cat("============================================================\n")
## ============================================================
cat("\n1. Mantener la base 4 en 1 como fuente principal para la predicción exploratoria de fruto visible.\n")
##
## 1. Mantener la base 4 en 1 como fuente principal para la predicción exploratoria de fruto visible.
cat("\n2. Usar la base Micro:bit exclusivamente para análisis temporal de humedad del suelo.\n")
##
## 2. Usar la base Micro:bit exclusivamente para análisis temporal de humedad del suelo.
cat("\n3. No reportar serie semanal 2026 mientras no exista una variable de fecha o semana.\n")
##
## 3. No reportar serie semanal 2026 mientras no exista una variable de fecha o semana.
cat("\n4. Ampliar el número de plantas evaluadas para mejorar la estabilidad de los modelos logísticos.\n")
##
## 4. Ampliar el número de plantas evaluadas para mejorar la estabilidad de los modelos logísticos.
cat("\n5. Registrar mediciones por planta en varios momentos si se desea construir modelos longitudinales o semanales de fruto.\n")
##
## 5. Registrar mediciones por planta en varios momentos si se desea construir modelos longitudinales o semanales de fruto.
cat("\n6. Incluir nuevas variables agronómicas como diámetro del tallo, número de hojas, producción por planta y estado sanitario.\n")
##
## 6. Incluir nuevas variables agronómicas como diámetro del tallo, número de hojas, producción por planta y estado sanitario.
cat("\n7. Integrar los resultados gráficos al tablero Semáforo del Cultivo en Power BI.\n")
##
## 7. Integrar los resultados gráficos al tablero Semáforo del Cultivo en Power BI.
cat("\n8. Interpretar todos los hallazgos como asociaciones exploratorias, no causales.\n")
##
## 8. Interpretar todos los hallazgos como asociaciones exploratorias, no causales.
cat("\n9. Hacer uso de mas sensores de microbit en estudios longitudinales.\n")
##
## 9. Hacer uso de mas sensores de microbit en estudios longitudinales.
cat("\n10. Generar un Tbalero agronomicos en el cultivo de café con el fin de hacer seguimiento continuo
a los procesos productivos.\n")
##
## 10. Generar un Tbalero agronomicos en el cultivo de café con el fin de hacer seguimiento continuo
## a los procesos productivos.
# ============================================================
# 29. CIERRE FINAL
# ============================================================
cat("\n============================================================\n")
##
## ============================================================
cat("CIERRE DEL ANÁLISIS\n")
## CIERRE DEL ANÁLISIS
cat("============================================================\n")
## ============================================================
cat("\nEl análisis final en RStudio permite contrastar los resultados previos de SPSS,\n")
##
## El análisis final en RStudio permite contrastar los resultados previos de SPSS,
cat("mantener la estructura metodológica del trabajo ya realizado y complementar el estudio\n")
## mantener la estructura metodológica del trabajo ya realizado y complementar el estudio
cat("con gráficos llamativos, análisis temporal por hora, correlaciones exploratorias y regresión logística.\n")
## con gráficos llamativos, análisis temporal por hora, correlaciones exploratorias y regresión logística.
cat("La predicción se limita a la base por planta y la serie temporal se limita a la humedad Micro:bit.\n")
## La predicción se limita a la base por planta y la serie temporal se limita a la humedad Micro:bit.
cat("Los resultados deben interpretarse como exploratorios y no causales.\n")
## Los resultados deben interpretarse como exploratorios y no causales.
cat("\n\nArchivos generados:\n")
##
##
## Archivos generados:
cat("1. resultados_cafe_rstudio/tablas/Resultados_contraste_RStudio_Cafe.xlsx\n")
## 1. resultados_cafe_rstudio/tablas/Resultados_contraste_RStudio_Cafe.xlsx
cat("2. Carpeta de gráficos: resultados_cafe_rstudio/graficos\n")
## 2. Carpeta de gráficos: resultados_cafe_rstudio/graficos
# ============================================================
# CIERRE DEL SCRIPT
# ============================================================