La variable HORA representa la hora del dia en la que fue registrado cada deslizamiento. Sus valores son enteros comprendidos entre 0 y 23, por lo que se clasifica como cuantitativa discreta.
Analizar la distribucion de los deslizamientos registrados segun la hora del dia en que ocurrieron, mediante conteos, agrupacion por Sturges, diagramas de barras, ojivas, boxplot e indicadores descriptivos.
library(readxl)
library(knitr)
archivo_dataset <- "dataset_deslizamientos_dia_hora.xlsx"
if (!file.exists(archivo_dataset)) {
stop(
paste(
"No se encontro el archivo",
archivo_dataset,
"en la carpeta de trabajo."
)
)
}
hojas_disponibles <- excel_sheets(
archivo_dataset
)
if ("Dataset_landslides" %in% hojas_disponibles) {
hoja_dataset <- "Dataset_landslides"
} else {
hoja_dataset <- hojas_disponibles[1]
}
datos <- read_excel(
archivo_dataset,
sheet = hoja_dataset
)
datos <- as.data.frame(
datos
)
resumen_dataset <- data.frame(
Elemento = c(
"Archivo utilizado",
"Hoja utilizada",
"Numero de filas",
"Numero de columnas",
"Variable analizada",
"Tipo de variable"
),
Descripcion = c(
basename(archivo_dataset),
hoja_dataset,
nrow(datos),
ncol(datos),
"Hora de ocurrencia del deslizamiento",
"Cuantitativa discreta"
)
)
knitr::kable(
resumen_dataset,
caption = "Resumen inicial del dataset"
)
| Elemento | Descripcion |
|---|---|
| Archivo utilizado | dataset_deslizamientos_dia_hora.xlsx |
| Hoja utilizada | Sheet1 |
| Numero de filas | 11033 |
| Numero de columnas | 32 |
| Variable analizada | Hora de ocurrencia del deslizamiento |
| Tipo de variable | Cuantitativa discreta |
if (!"HORA" %in% names(datos)) {
stop(
paste(
"No se encontro la columna HORA.",
"Revise que el nombre sea exactamente HORA."
)
)
}
HORA_original <- suppressWarnings(
as.numeric(datos$HORA)
)
total_registros <- length(
HORA_original
)
datos_faltantes <- sum(
is.na(HORA_original)
)
datos_fuera_dominio <- sum(
!is.na(HORA_original) &
(
HORA_original < 0 |
HORA_original > 23 |
HORA_original %% 1 != 0
)
)
HORA <- HORA_original[
!is.na(HORA_original) &
HORA_original >= 0 &
HORA_original <= 23 &
HORA_original %% 1 == 0
]
HORA <- as.integer(
HORA
)
n <- length(
HORA
)
if (n == 0) {
stop(
"No existen datos validos en la variable HORA."
)
}
tabla_extraccion <- data.frame(
Indicador = c(
"Registros originales",
"Datos faltantes",
"Datos fuera del dominio",
"Datos validos utilizados"
),
Resultado = c(
total_registros,
datos_faltantes,
datos_fuera_dominio,
n
)
)
knitr::kable(
tabla_extraccion,
caption = "Control de extraccion de la variable HORA"
)
| Indicador | Resultado |
|---|---|
| Registros originales | 11033 |
| Datos faltantes | 0 |
| Datos fuera del dominio | 0 |
| Datos validos utilizados | 11033 |
hora_cero_n <- sum(HORA == 0)
hora_cero_pct <- hora_cero_n / n * 100
La hora 0 pertenece al dominio de la variable y representa las 00:00. En el dataset aparece en 5584 registros (50.61 %). La interpretacion debe hacerse con cautela si la fuente original empleo 0 para una hora no especificada.
conteo_inicial <- data.frame(
Indicador = c(
"Numero de datos validos",
"Valor minimo",
"Valor maximo",
"Valores diferentes"
),
Resultado = c(
n,
min(HORA),
max(HORA),
length(unique(HORA))
)
)
knitr::kable(
conteo_inicial,
caption = "Conteo inicial de la variable HORA"
)
| Indicador | Resultado |
|---|---|
| Numero de datos validos | 11033 |
| Valor minimo | 0 |
| Valor maximo | 23 |
| Valores diferentes | 24 |
La variable HORA posee 24 valores posibles y el dataset
contiene una gran cantidad de registros. Una tabla con el conteo de cada
valor es util para la revision individual, pero para resumir la
distribucion se aplica la regla de Sturges y se construyen intervalos
agrupados.
El valor cero se conserva porque pertenece al dominio horario y representa las 00:00. Sin embargo, su interpretacion debe realizarse con cautela si en la fuente original el valor 0 tambien fue utilizado para registrar una hora desconocida:
\[ HORA=\{0,1,2,\ldots,23\} \]
La regla de Sturges se expresa como:
\[ k=1+3.322\log_{10}(n) \]
valor_sturges <- 1 +
3.322 *
log10(n)
numero_clases <- ceiling(
valor_sturges
)
valor_minimo <- min(
HORA
)
valor_maximo <- max(
HORA
)
limite_inicial <- valor_minimo - 0.5
limite_final <- valor_maximo + 0.5
rango_real <- limite_final -
limite_inicial
amplitud_clase <- rango_real /
numero_clases
limites_clase <- seq(
from = limite_inicial,
to = limite_final,
length.out = numero_clases + 1
)
limites_inferiores <- head(
limites_clase,
-1
)
limites_superiores <- tail(
limites_clase,
-1
)
marcas_clase <- (
limites_inferiores +
limites_superiores
) / 2
intervalos_texto <- paste0(
"[",
round(limites_inferiores, 2),
" ; ",
round(limites_superiores, 2),
")"
)
tabla_sturges <- data.frame(
Elemento = c(
"Numero de datos",
"Resultado de Sturges",
"Numero de clases",
"Limite inicial",
"Limite final",
"Rango real",
"Amplitud de clase"
),
Resultado = c(
n,
valor_sturges,
numero_clases,
limite_inicial,
limite_final,
rango_real,
amplitud_clase
)
)
knitr::kable(
tabla_sturges,
digits = 4,
caption = "Aplicacion de Sturges y definicion de clases"
)
| Elemento | Resultado |
|---|---|
| Numero de datos | 11033.00 |
| Resultado de Sturges | 14.43 |
| Numero de clases | 15.00 |
| Limite inicial | -0.50 |
| Limite final | 23.50 |
| Rango real | 24.00 |
| Amplitud de clase | 1.60 |
Se obtuvieron 15 clases con una amplitud aproximada de 1.6 horas.
Las barras se presentan separadas para conservar la lectura de una variable discreta.
clase_hora <- cut(
HORA,
breaks = limites_clase,
include.lowest = TRUE,
right = FALSE,
dig.lab = 5
)
ni_agrupada <- as.numeric(
table(clase_hora)
)
hi_agrupada <- ni_agrupada /
n
Ni_agrupada <- cumsum(
ni_agrupada
)
porcentaje_acumulado_ascendente <- c(
0,
Ni_agrupada /
n *
100
)
porcentaje_acumulado_descendente <- c(
100,
100 -
Ni_agrupada /
n *
100
)
horas_completas <- 0:23
conteo_horas <- table(
factor(
HORA,
levels = horas_completas
)
)
tabla_individual <- data.frame(
Hora = horas_completas,
ni = as.numeric(conteo_horas)
)
tabla_individual$hi <- tabla_individual$ni /
n
knitr::kable(
tabla_individual,
digits = 4,
col.names = c(
"Hora del dia",
"ni",
"hi"
),
caption = "Tabla Nro. 1. Conteo individual de las horas de ocurrencia"
)
| Hora del dia | ni | hi |
|---|---|---|
| 0 | 5584 | 0.5061 |
| 1 | 78 | 0.0071 |
| 2 | 115 | 0.0104 |
| 3 | 101 | 0.0092 |
| 4 | 119 | 0.0108 |
| 5 | 93 | 0.0084 |
| 6 | 104 | 0.0094 |
| 7 | 98 | 0.0089 |
| 8 | 296 | 0.0268 |
| 9 | 604 | 0.0547 |
| 10 | 121 | 0.0110 |
| 11 | 83 | 0.0075 |
| 12 | 148 | 0.0134 |
| 13 | 537 | 0.0487 |
| 14 | 389 | 0.0353 |
| 15 | 448 | 0.0406 |
| 16 | 237 | 0.0215 |
| 17 | 219 | 0.0198 |
| 18 | 391 | 0.0354 |
| 19 | 205 | 0.0186 |
| 20 | 225 | 0.0204 |
| 21 | 148 | 0.0134 |
| 22 | 140 | 0.0127 |
| 23 | 550 | 0.0499 |
tabla_agrupada <- data.frame(
Clase = seq_len(numero_clases),
Intervalo = intervalos_texto,
ni = ni_agrupada,
hi = hi_agrupada
)
knitr::kable(
tabla_agrupada,
digits = 4,
col.names = c(
"Clase",
"Intervalo",
"ni",
"hi"
),
caption = "Tabla Nro. 2. Distribucion agrupada de las horas mediante Sturges"
)
| Clase | Intervalo | ni | hi |
|---|---|---|---|
| 1 | [-0.5 ; 1.1) | 5662 | 0.5132 |
| 2 | [1.1 ; 2.7) | 115 | 0.0104 |
| 3 | [2.7 ; 4.3) | 220 | 0.0199 |
| 4 | [4.3 ; 5.9) | 93 | 0.0084 |
| 5 | [5.9 ; 7.5) | 202 | 0.0183 |
| 6 | [7.5 ; 9.1) | 900 | 0.0816 |
| 7 | [9.1 ; 10.7) | 121 | 0.0110 |
| 8 | [10.7 ; 12.3) | 231 | 0.0209 |
| 9 | [12.3 ; 13.9) | 537 | 0.0487 |
| 10 | [13.9 ; 15.5) | 837 | 0.0759 |
| 11 | [15.5 ; 17.1) | 456 | 0.0413 |
| 12 | [17.1 ; 18.7) | 391 | 0.0354 |
| 13 | [18.7 ; 20.3) | 430 | 0.0390 |
| 14 | [20.3 ; 21.9) | 148 | 0.0134 |
| 15 | [21.9 ; 23.5) | 690 | 0.0625 |
par(
mar = c(5, 5, 5, 2)
)
posiciones_cantidad <- barplot(
height = tabla_individual$ni,
names.arg = tabla_individual$Hora,
space = 0.20,
col = "#E9D8C2",
border = "#444444",
main = paste0(
"Grafica Nro. 1: Cantidad de deslizamientos\n",
"segun la hora del dia"
),
xlab = "Hora de ocurrencia",
ylab = "Cantidad",
cex.names = 0.72,
las = 1,
ylim = c(
0,
max(tabla_individual$ni) * 1.18
)
)
text(
x = posiciones_cantidad,
y = tabla_individual$ni,
labels = tabla_individual$ni,
pos = 3,
cex = 0.58,
font = 2
)
porcentaje_individual <- tabla_individual$hi *
100
par(
mar = c(5, 5, 5, 2)
)
posiciones_porcentaje <- barplot(
height = porcentaje_individual,
names.arg = tabla_individual$Hora,
space = 0.20,
col = "#CFA6B8",
border = "#444444",
main = paste0(
"Grafica Nro. 2: Porcentaje de deslizamientos\n",
"segun la hora del dia"
),
xlab = "Hora de ocurrencia",
ylab = "Porcentaje",
cex.names = 0.72,
las = 1,
ylim = c(
0,
max(porcentaje_individual) * 1.18
)
)
text(
x = posiciones_porcentaje,
y = porcentaje_individual,
labels = round(porcentaje_individual, 2),
pos = 3,
cex = 0.52,
font = 2
)
par(
mar = c(8, 5, 5, 2)
)
posiciones_agrupadas <- barplot(
height = ni_agrupada,
names.arg = intervalos_texto,
space = 0.25,
col = "#E9D8C2",
border = "#333333",
main = paste0(
"Grafica Nro. 3: Cantidad agrupada de deslizamientos\n",
"segun los intervalos obtenidos mediante Sturges"
),
xlab = "Intervalos de la hora de ocurrencia",
ylab = "Cantidad",
las = 2,
cex.names = 0.62,
ylim = c(
0,
max(ni_agrupada) * 1.18
)
)
text(
x = posiciones_agrupadas,
y = ni_agrupada,
labels = ni_agrupada,
pos = 3,
cex = 0.75,
font = 2
)
puntos_ojiva <- limites_clase
par(
mar = c(5, 5, 5, 2)
)
plot(
puntos_ojiva,
porcentaje_acumulado_ascendente,
type = "o",
pch = 16,
lwd = 2,
col = "#F39C12",
main = paste0(
"Grafica Nro. 4: Distribucion acumulada porcentual\n",
"mediante ojivas ascendente y descendente"
),
xlab = "Limites de clase de la hora de ocurrencia",
ylab = "Porcentaje",
xlim = range(puntos_ojiva),
ylim = c(0, 100),
las = 1
)
grid(
col = "gray85",
lty = 1
)
lines(
puntos_ojiva,
porcentaje_acumulado_ascendente,
type = "o",
pch = 16,
lwd = 2,
col = "#F39C12"
)
lines(
puntos_ojiva,
porcentaje_acumulado_descendente,
type = "o",
pch = 16,
lwd = 2,
col = "#1F45FC"
)
legend(
"bottomright",
legend = c(
"Ascendente (Menor que)",
"Descendente (Mayor que)"
),
col = c(
"#F39C12",
"#1F45FC"
),
pch = 16,
lty = 1,
lwd = 2,
bg = "white",
bty = "o"
)
par(
mar = c(5, 5, 5, 2)
)
boxplot(
HORA,
horizontal = TRUE,
col = "#A7D3E8",
border = "#222222",
outline = TRUE,
outpch = 1,
outcol = "red",
main = paste0(
"Grafica Nro. 5: Diagrama de caja y bigotes\n",
"de la hora de ocurrencia"
),
xlab = "Hora de ocurrencia",
las = 1
)
frecuencia_maxima <- max(
ni_agrupada
)
limite_y_superior <- frecuencia_maxima *
1.25
posicion_boxplot <- frecuencia_maxima *
0.55
altura_boxplot <- frecuencia_maxima *
0.18
estadisticas_boxplot <- boxplot.stats(
HORA
)
bigote_inferior <- estadisticas_boxplot$stats[1]
primer_cuartil <- estadisticas_boxplot$stats[2]
mediana_boxplot <- estadisticas_boxplot$stats[3]
tercer_cuartil <- estadisticas_boxplot$stats[4]
bigote_superior <- estadisticas_boxplot$stats[5]
atipicos_boxplot <- estadisticas_boxplot$out
ancho_gap <- amplitud_clase *
0.08
par(
mar = c(5, 5, 5, 2)
)
plot(
NA,
xlim = c(limite_inicial, limite_final),
ylim = c(0, limite_y_superior),
main = paste0(
"Grafica Nro. 6: Cantidad agrupada de deslizamientos\n",
"con boxplot superpuesto"
),
xlab = "Hora de ocurrencia",
ylab = "Cantidad",
xaxt = "n",
las = 1
)
axis(
side = 1,
at = marcas_clase,
labels = round(marcas_clase, 1),
cex.axis = 0.75
)
for (i in seq_len(numero_clases)) {
rect(
xleft = limites_inferiores[i] + ancho_gap,
ybottom = 0,
xright = limites_superiores[i] - ancho_gap,
ytop = ni_agrupada[i],
col = "#E9D8C2",
border = "#333333"
)
}
text(
x = marcas_clase,
y = ni_agrupada,
labels = ni_agrupada,
pos = 3,
cex = 0.78,
font = 2
)
segments(
x0 = bigote_inferior,
y0 = posicion_boxplot,
x1 = bigote_superior,
y1 = posicion_boxplot,
lty = 2,
lwd = 1.5,
col = "#333333"
)
segments(
x0 = bigote_inferior,
y0 = posicion_boxplot - altura_boxplot * 0.18,
x1 = bigote_inferior,
y1 = posicion_boxplot + altura_boxplot * 0.18,
lwd = 1.5
)
segments(
x0 = bigote_superior,
y0 = posicion_boxplot - altura_boxplot * 0.18,
x1 = bigote_superior,
y1 = posicion_boxplot + altura_boxplot * 0.18,
lwd = 1.5
)
rect(
xleft = primer_cuartil,
ybottom = posicion_boxplot - altura_boxplot / 2,
xright = tercer_cuartil,
ytop = posicion_boxplot + altura_boxplot / 2,
col = "#A7D3E8",
border = "#222222",
lwd = 1.3
)
segments(
x0 = mediana_boxplot,
y0 = posicion_boxplot - altura_boxplot / 2,
x1 = mediana_boxplot,
y1 = posicion_boxplot + altura_boxplot / 2,
lwd = 3,
col = "#111111"
)
if (length(atipicos_boxplot) > 0) {
points(
x = atipicos_boxplot,
y = rep(
posicion_boxplot,
length(atipicos_boxplot)
),
pch = 1,
col = "red",
cex = 1.1,
lwd = 1.3
)
}
media_hora <- mean(
HORA
)
mediana_hora <- median(
HORA
)
frecuencias_moda <- table(
HORA
)
frecuencia_maxima_moda <- max(
frecuencias_moda
)
modas_hora <- as.numeric(
names(
frecuencias_moda[
frecuencias_moda ==
frecuencia_maxima_moda
]
)
)
texto_moda <- paste(
modas_hora,
collapse = ", "
)
rango_texto <- paste0(
min(HORA),
" - ",
max(HORA)
)
varianza_hora <- var(
HORA
)
desviacion_hora <- sd(
HORA
)
coeficiente_variacion <- (
desviacion_hora /
media_hora
) * 100
momento_2 <- mean(
(HORA - media_hora)^2
)
momento_3 <- mean(
(HORA - media_hora)^3
)
momento_4 <- mean(
(HORA - media_hora)^4
)
asimetria_hora <- momento_3 /
momento_2^(3 / 2)
curtosis_hora <- (
momento_4 /
momento_2^2
) - 3
valores_atipicos <- boxplot.stats(
HORA
)$out
cantidad_atipicos <- length(
valores_atipicos
)
texto_valores_atipicos <- if (
cantidad_atipicos == 0
) {
"No existen"
} else {
paste0(
cantidad_atipicos,
" valores entre ",
min(valores_atipicos),
" y ",
max(valores_atipicos)
)
}
interpretacion_cv <- ifelse(
coeficiente_variacion <= 30,
"homogeneos",
"heterogeneos"
)
interpretacion_asimetria <- ifelse(
asimetria_hora > 0.10,
"asimetria positiva hacia la derecha",
ifelse(
asimetria_hora < -0.10,
"asimetria negativa hacia la izquierda",
"distribucion aproximadamente simetrica"
)
)
interpretacion_curtosis <- ifelse(
curtosis_hora > 0.10,
"leptocurtica",
ifelse(
curtosis_hora < -0.10,
"platicurtica",
"mesocurtica"
)
)
clase_modal <- which.max(
ni_agrupada
)
centro_intervalo_modal <- marcas_clase[
clase_modal
]
tercio_1 <- limite_inicial +
rango_real / 3
tercio_2 <- limite_inicial +
2 * rango_real / 3
parte_variable <- ifelse(
centro_intervalo_modal <= tercio_1,
"parte baja",
ifelse(
centro_intervalo_modal <= tercio_2,
"parte media",
"parte alta"
)
)
intervalo_modal_texto <- intervalos_texto[
clase_modal
]
tabla_indicadores <- data.frame(
Medida = c(
"Media",
"Mediana",
"Moda",
"Rango",
"Varianza",
"Desviacion estandar",
"Coeficiente de variacion (%)",
"Asimetria",
"Curtosis",
"Valores atipicos"
),
Valor = c(
round(media_hora, 2),
round(mediana_hora, 2),
texto_moda,
rango_texto,
round(varianza_hora, 2),
round(desviacion_hora, 2),
round(coeficiente_variacion, 2),
round(asimetria_hora, 2),
round(curtosis_hora, 2),
texto_valores_atipicos
)
)
knitr::kable(
tabla_indicadores,
col.names = c(
"Medida",
"Valor"
),
caption = "Tabla Nro. 3. Indicadores estadisticos de la variable HORA"
)
| Medida | Valor |
|---|---|
| Media | 6.84 |
| Mediana | 0 |
| Moda | 0 |
| Rango | 0 - 23 |
| Varianza | 64.84 |
| Desviacion estandar | 8.05 |
| Coeficiente de variacion (%) | 117.68 |
| Asimetria | 0.66 |
| Curtosis | -1.09 |
| Valores atipicos | No existen |
La variable hora de ocurrencia fluctua entre 0 y 23 horas, y sus valores giran alrededor de un promedio de 6.84 horas, con una desviacion estandar de 8.05 horas. De acuerdo con el coeficiente de variacion, los datos son heterogeneos. La mayor presencia de registros se encuentra en el intervalo [-0.5 ; 1.1), ubicado en la parte baja de la variable. La distribucion presenta asimetria positiva hacia la derecha y una forma platicurtica, sin presencia de valores atipicos. Este comportamiento no se considera beneficioso ni perjudicial por si mismo, pero permite identificar la concentracion temporal de los registros a lo largo del dia. Debido a que la hora 0 representa 50.61% de los datos, debe confirmarse si todos esos registros corresponden realmente a las 00:00 o si algunos representan una hora no especificada.