DISTRIBUCIONES DE FRECUENCIAS

TALLER_1

Autor/a
Afiliación

Daniel Gutierrez Barrera
Andres Caro
Nicolas Diaz

Fecha de publicación

5 de abril de 2026

Logo Universidad del Tolima

1 Cargar paquetes

Ver código
ipak <- function(pkg){
  
  # Definir repositorio CRAN (evita el error del mirror)
  options(repos = c(CRAN = "https://cloud.r-project.org"))
  
  # Identificar paquetes instalados
  installed <- rownames(installed.packages())
  
  # Identificar paquetes faltantes
  new.pkg <- setdiff(pkg, installed)
  
  # Instalar paquetes faltantes
  if(length(new.pkg) > 0){
    install.packages(new.pkg, dependencies = TRUE)
  }
  
  # Cargar paquetes sin mostrar mensajes
  invisible(lapply(pkg, function(p){
    suppressPackageStartupMessages(
      library(p, character.only = TRUE)
    )
  }))
}

# Crear la lista de los paquetes a utilizar
packages <- c("tidyverse", "kableExtra", "psych", "readxl", "stringi")

# Instalar y cargar los paquetes del listado anterior
ipak(packages)

(Wickham et al. 2019; Zhu 2024; 2026; Wickham y Bryan 2025)

2 Introducción

2.1 Distribución de Frecuencias

- Concepto

Una distribución de frecuencias es una forma de organizar, resumir y presentar datos estadísticos mediante tablas que muestran el número de observaciones que pertenecen a cada categoría o intervalo de una variable.

Formalmente, si se tiene un conjunto de datos:

X = \{x_1, x_2, x_3, \dots , x_n\}

la distribución de frecuencias permite identificar cuántas veces aparece cada valor o intervalo dentro del conjunto de datos.

Las distribuciones de frecuencias se utilizan para:

  • Resumir grandes volúmenes de datos
  • Identificar patrones en los datos
  • Facilitar la construcción de gráficos estadísticos
  • Calcular medidas estadísticas (media, varianza, etc.)

- Elementos de una Distribución de Frecuencias

Elemento Descripción
Clase o categoría Valores o intervalos de la variable
Frecuencia absoluta Número de veces que aparece un valor
Frecuencia relativa Proporción del total
Frecuencia acumulada Suma progresiva de frecuencias
Marca de clase Punto medio del intervalo

- Frecuencia Absoluta

La frecuencia absoluta indica cuántas veces aparece un valor o categoría en el conjunto de datos.

Se denota por:

f_i

La suma de todas las frecuencias absolutas es igual al tamaño de la muestra:

\sum_{i=1}^{k} f_i = n

- Frecuencia Relativa

La frecuencia relativa representa la proporción de datos que pertenecen a una categoría.

h_i = \frac{f_i}{n}

La suma de todas las frecuencias relativas es:

\sum_{i=1}^{k} h_i = 1

Si se expresa en porcentaje:

h_i(\%) = \frac{f_i}{n} \times 100

- Frecuencia Acumulada

La frecuencia acumulada corresponde a la suma progresiva de las frecuencias absolutas hasta una clase determinada.

F_i = \sum_{j=1}^{i} f_j

Propiedad:

F_k = n

- Frecuencia Relativa Acumulada

La frecuencia relativa acumulada se obtiene acumulando las frecuencias relativas:

H_i = \sum_{j=1}^{i} h_j

También puede calcularse como:

H_i = \frac{F_i}{n}

Propiedad:

H_k = 1

2.2 Distribución de Frecuencias para Datos Agrupados

Un intervalo se define como:

(L_i, L_s)

- Número de Clases (Regla de Sturges)

Para determinar el número adecuado de clases se usa frecuentemente la regla de Sturges:

k = 1 + 3.322 \log_{10}(n)

- Amplitud de Clase

A = \frac{R}{k}

El rango se calcula como:

R = X_{max} - X_{min}

- Marca de Clase

x_i = \frac{L_i + L_s}{2}

3 El Dataset

3.1 Bajar el Dataset

Base de datos de la encuesta

3.2 Leer el Dataset

Ver código
deporte <- read_excel("deporte.xlsx")

3.3 Conocer el Dataset

- Mostrar algunas filas del dataset

Ver código
head(deporte)
# A tibble: 6 × 13
  GENERO   DEPORTE ESCOLARIDAD DESEMPEÑO PRACTICAS  EDAD  PESO LESIONES ESTATURA
  <chr>    <chr>   <chr>       <chr>         <dbl> <dbl> <dbl>    <dbl>    <dbl>
1 Masculi… Fútbol  Posgrado    Medio             5    44    56        2      180
2 Masculi… Voleib… Pregrado    Medio             5    59    66        1      152
3 Femenino Gimnas… Posgrado    Alto              4    27    57        2      157
4 Masculi… Nataci… Secundaria  Alto              3    44    54        3      167
5 Femenino Nataci… Posgrado    Medio             4    59    73        0      189
6 Masculi… Nataci… Pregrado    Bajo              2    58    59        1      188
# ℹ 4 more variables: BORG <dbl>, EVA <dbl>, CINTURA <dbl>, CADERA <dbl>

- Estructura de las Variables

Ver código
glimpse(deporte)
Rows: 200
Columns: 13
$ GENERO      <chr> "Masculino", "Masculino", "Femenino", "Masculino", "Femeni…
$ DEPORTE     <chr> "Fútbol", "Voleibol", "Gimnasia", "Natación", "Natación", …
$ ESCOLARIDAD <chr> "Posgrado", "Pregrado", "Posgrado", "Secundaria", "Posgrad…
$ DESEMPEÑO   <chr> "Medio", "Medio", "Alto", "Alto", "Medio", "Bajo", "Bajo",…
$ PRACTICAS   <dbl> 5, 5, 4, 3, 4, 2, 4, 5, 6, 1, 7, 3, 2, 7, 5, 2, 4, 2, 7, 5…
$ EDAD        <dbl> 44, 59, 27, 44, 59, 58, 21, 40, 54, 46, 35, 54, 38, 38, 53…
$ PESO        <dbl> 56, 66, 57, 54, 73, 59, 69, 55, 65, 69, 56, 53, 54, 80, 59…
$ LESIONES    <dbl> 2, 1, 2, 3, 0, 1, 0, 0, 0, 3, 2, 2, 0, 2, 2, 1, 3, 0, 1, 1…
$ ESTATURA    <dbl> 180, 152, 157, 167, 189, 188, 169, 185, 166, 155, 150, 187…
$ BORG        <dbl> 5, 3, 2, 6, 1, 7, 10, 5, 9, 6, 7, 10, 8, 0, 1, 0, 9, 3, 7,…
$ EVA         <dbl> 0, 4, 2, 4, 2, 2, 4, 2, 2, 4, 1, 0, 4, 1, 1, 3, 0, 5, 5, 4…
$ CINTURA     <dbl> 120, 139, 143, 120, 74, 143, 116, 97, 74, 93, 122, 71, 112…
$ CADERA      <dbl> 88, 94, 90, 99, 94, 89, 95, 95, 92, 95, 87, 109, 102, 88, …

- Número de Variables

Ver código
deporte %>% names %>% length
[1] 13

- Nombre de las Variables

Ver código
names(deporte)
 [1] "GENERO"      "DEPORTE"     "ESCOLARIDAD" "DESEMPEÑO"   "PRACTICAS"  
 [6] "EDAD"        "PESO"        "LESIONES"    "ESTATURA"    "BORG"       
[11] "EVA"         "CINTURA"     "CADERA"     

3.4 Transformar Variables

Ver código
deporte$GENERO <- as.factor(deporte$GENERO)
deporte$DEPORTE <- as.factor(deporte$DEPORTE)

deporte$ESCOLARIDAD <- factor(deporte$ESCOLARIDAD,
  levels = c("Primaria","Secundaria","Pregrado","Posgrado"), ordered = TRUE)

deporte$DESEMPEÑO <- factor(deporte$DESEMPEÑO,
  levels = c("Bajo","Medio","Alto"), ordered = TRUE)

3.5 Nueva estructura de las variables

Ver código
glimpse(deporte)
Rows: 200
Columns: 13
$ GENERO      <fct> Masculino, Masculino, Femenino, Masculino, Femenino, Mascu…
$ DEPORTE     <fct> Fútbol, Voleibol, Gimnasia, Natación, Natación, Natación, …
$ ESCOLARIDAD <ord> Posgrado, Pregrado, Posgrado, Secundaria, Posgrado, Pregra…
$ DESEMPEÑO   <ord> Medio, Medio, Alto, Alto, Medio, Bajo, Bajo, Bajo, Medio, …
$ PRACTICAS   <dbl> 5, 5, 4, 3, 4, 2, 4, 5, 6, 1, 7, 3, 2, 7, 5, 2, 4, 2, 7, 5…
$ EDAD        <dbl> 44, 59, 27, 44, 59, 58, 21, 40, 54, 46, 35, 54, 38, 38, 53…
$ PESO        <dbl> 56, 66, 57, 54, 73, 59, 69, 55, 65, 69, 56, 53, 54, 80, 59…
$ LESIONES    <dbl> 2, 1, 2, 3, 0, 1, 0, 0, 0, 3, 2, 2, 0, 2, 2, 1, 3, 0, 1, 1…
$ ESTATURA    <dbl> 180, 152, 157, 167, 189, 188, 169, 185, 166, 155, 150, 187…
$ BORG        <dbl> 5, 3, 2, 6, 1, 7, 10, 5, 9, 6, 7, 10, 8, 0, 1, 0, 9, 3, 7,…
$ EVA         <dbl> 0, 4, 2, 4, 2, 2, 4, 2, 2, 4, 1, 0, 4, 1, 1, 3, 0, 5, 5, 4…
$ CINTURA     <dbl> 120, 139, 143, 120, 74, 143, 116, 97, 74, 93, 122, 71, 112…
$ CADERA      <dbl> 88, 94, 90, 99, 94, 89, 95, 95, 92, 95, 87, 109, 102, 88, …

4 Tablas y Gráficas

4.1 Variable Nominal

AdvertenciaLa variable nominal tiene solo frecuencia absoluta, relativa y porcentaje

*Tabla No. 1: Distribución de frecuencias de los sujetos según el género/**

Ver código
tabla_final_genero <- tibble(GENERO = deporte$GENERO) %>% 
  group_by(GENERO) %>% 
  summarise(fi = n()) %>% 
  mutate(
    hi = round(fi/sum(fi), 4), 
    Porcentaje = paste0(hi*100, "%")
  ) %>% 
  mutate(GENERO = as.character(GENERO)) %>% 
  bind_rows(
    tibble(
      GENERO = "Total",
      fi = sum(.$fi),
      hi = round(sum(.$hi), 4),
      Porcentaje = paste0(round(sum(.$hi)*100, 2), "%")
    )
  )

tabla_final_genero %>% 
  knitr::kable(
    col.names = c("Género", "fi", "hi", "Porcentaje"), 
    align = c("l", "c", "c", "c"),
    escape = FALSE
  ) %>% 
  kableExtra::kable_styling(full_width = FALSE) %>% 
  kableExtra::row_spec(
    nrow(tabla_final_genero), 
    color = "white", 
    background = "red",
    bold = TRUE
  )
Género fi hi Porcentaje
Femenino 93 0.465 46.5%
Masculino 107 0.535 53.5%
Total 200 1.000 100%
Ver código
genero_counts <- tibble(GENERO = deporte$GENERO) %>% 
  group_by(GENERO) %>% 
  summarise(fi = n()) %>% 
  mutate(
    porcentaje = fi/sum(fi)*100
  )

ggplot(genero_counts, aes(x = GENERO, y = porcentaje, fill = GENERO)) +
  geom_bar(stat = "identity") +
  labs(title = "Distribución porcentual según el género", 
       x = "Género", 
       y = "Porcentaje") +
  theme_minimal() +
  theme(legend.position = "none") +
  geom_text(aes(label = sprintf("%.1f%%", porcentaje)), 
            vjust = -0.5, 
            size = 3.5)

Ver código
ggplot(genero_counts, aes(x = "", y = porcentaje, fill = GENERO)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y") +
  labs(title = "Distribución porcentual según el género") +
  theme_minimal() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.grid = element_blank(),
        axis.text.x = element_blank()) +
  geom_text(aes(label = sprintf("%.1f%%", porcentaje)), 
            position = position_stack(vjust = 0.5), 
            color = "white", 
            size = 4)

La tabla muestra la distribución de frecuencias de los sujetos según el género en una muestra de 200 individuos. Se observa que el 53.5% (107 sujetos) corresponde al género masculino, mientras que el 46.5% (93 sujetos) pertenece al género femenino. Esto evidencia una ligera predominancia del género masculino, con una diferencia de 7 puntos porcentuales respecto al femenino. No obstante, la distribución puede considerarse relativamente equilibrada, ya que ambos grupos presentan proporciones cercanas. En conjunto, los datos reflejan una composición casi homogénea por género dentro de la muestra analizada.


4.2 Variable Ordinal

TipLa variable ordinal tiene los cuatro tipos de frecuencias

Tabla No. 2. Distribución de los sujetos según los niveles de EVA

Ver código
library(dplyr)
library(tibble)
library(knitr)
library(kableExtra)

tabla_final <- tibble(EVA = deporte$EVA) %>% 
  group_by(EVA) %>% 
  summarise(fi = n(), .groups = "drop") %>% 
  arrange(EVA) %>% 
  mutate(
    hi = round(fi / sum(fi), 4),
    Porcentaje = paste0(hi * 100, "%"),
    Fi = cumsum(fi),
    Hi = round(cumsum(hi), 4)
  ) %>% 
  mutate(
    EVA = as.character(EVA)
  ) %>% 
  bind_rows(
    tibble(
      EVA = "Total",
      fi = sum(.$fi),
      hi = round(sum(.$hi), 4),
      Porcentaje = paste0(round(sum(.$hi) * 100, 2), "%"),
      Fi = sum(.$fi),
      Hi = 1
    )
  )

tabla_final %>% 
  knitr::kable(
    col.names = c("EVA", "fi", "hi", "Porcentaje", "Fi", "Hi"), 
    align = c("l", "c", "c", "c", "c", "c")
  ) %>% 
  kableExtra::kable_styling(full_width = FALSE) %>% 
  kableExtra::row_spec(
    nrow(tabla_final), 
    color = "white", 
    background = "red",
    bold = TRUE
  )
EVA fi hi Porcentaje Fi Hi
0 28 0.140 14% 28 0.140
1 39 0.195 19.5% 67 0.335
2 35 0.175 17.5% 102 0.510
3 31 0.155 15.5% 133 0.665
4 31 0.155 15.5% 164 0.820
5 36 0.180 18% 200 1.000
Total 200 1.000 100% 200 1.000
Ver código
library(dplyr)
library(tibble)
library(ggplot2)

eva_counts <- tibble(EVA = deporte$EVA) %>% 
  filter(!is.na(EVA)) %>% 
  group_by(EVA) %>% 
  summarise(fi = n(), .groups = "drop") %>% 
  arrange(EVA) %>% 
  mutate(
    porcentaje = fi / sum(fi) * 100
  )

ggplot(eva_counts, aes(x = factor(EVA, levels = sort(unique(EVA))), 
                       y = porcentaje, 
                       fill = factor(EVA))) +
  geom_bar(stat = "identity") +
  labs(
    title = "Distribución porcentual según los niveles de la Escala Visual Análoga (EVA)",
    x = "Niveles de EVA",
    y = "Porcentaje"
  ) +
  theme_minimal() +
  theme(legend.position = "none") +
  geom_text(
    aes(label = sprintf("%.1f%%", porcentaje)), 
    vjust = -0.5, 
    size = 3.5
  )

La distribución de la muestra según los niveles de la Escala Visual Análoga (EVA) evidencia que los valores se encuentran relativamente dispersos a lo largo de toda la escala (0 a 5), sin una concentración extrema en un único nivel. El nivel más frecuente corresponde a EVA = 1, con una frecuencia de 39 sujetos (19,5%), seguido por los niveles EVA = 5 (18%) y EVA = 2 (17,5%). Por otro lado, los niveles EVA = 3 y EVA = 4 presentan proporciones iguales (15,5% cada uno), mientras que el valor más bajo (EVA = 0) representa el 14% de la muestra. Desde el punto de vista acumulado, el 51% de los sujetos se concentra en valores de EVA iguales o inferiores a 2, lo que sugiere una ligera tendencia hacia niveles bajos a moderados en la escala. Sin embargo, el 49% restante se distribuye en valores superiores (3 a 5), indicando también una presencia importante de niveles más altos. En conjunto, los resultados muestran una distribución relativamente equilibrada, con una leve predominancia de valores bajos, lo cual podría interpretarse como una percepción general moderada en la variable evaluada mediante la escala EVA.

4.3 Variable Discreta

AdvertenciaLa variable discreta tiene los cuatro tipos de frecuencias

Tabla No.3: Análisis de la frecuencia de prácticas semanales en un grupo de personas

Ver código
library(dplyr)
library(tibble)
library(knitr)
library(kableExtra)

tabla_final <- tibble(PRACTICAS = deporte$PRACTICAS) %>% 
  filter(!is.na(PRACTICAS)) %>% 
  group_by(PRACTICAS) %>% 
  summarise(fi = n(), .groups = "drop") %>% 
  arrange(PRACTICAS) %>% 
  mutate(
    hi = round(fi/sum(fi), 4), 
    Porcentaje = paste0(hi*100, "%"),
    Fi = cumsum(fi),
    Hi = format(round(cumsum(hi), 4), nsmall = 3)
  ) %>% 
  mutate(
    PRACTICAS = as.character(PRACTICAS),
    Fi = as.character(Fi)
  ) %>% 
  bind_rows(
    tibble(
      PRACTICAS = "Total",
      fi = sum(.$fi),
      hi = round(sum(as.numeric(.$hi)), 4),
      Porcentaje = paste0(round(sum(as.numeric(.$hi))*100, 2), "%"),
      Fi = as.character(sum(.$fi)),
      Hi = format(1, nsmall = 3)
    )
  )

tabla_final %>% 
  knitr::kable(
    col.names = c("Prácticas", "fi", "hi", "Porcentaje", "Fi", "Hi"), 
    align = c("l", "c", "c", "c", "c", "c")
  ) %>% 
  kableExtra::kable_styling(full_width = FALSE) %>% 
  kableExtra::row_spec(
    nrow(tabla_final), 
    color = "white", 
    background = "red",
    bold = TRUE
  )
Prácticas fi hi Porcentaje Fi Hi
1 27 0.135 13.5% 27 0.135
2 26 0.130 13% 53 0.265
3 22 0.110 11% 75 0.375
4 33 0.165 16.5% 108 0.540
5 29 0.145 14.5% 137 0.685
6 33 0.165 16.5% 170 0.850
7 30 0.150 15% 200 1.000
Total 200 1.000 100% 200 1.000
Ver código
library(dplyr)
library(tibble)
library(ggplot2)

df <- deporte %>% 
  select(PRACTICAS) %>% 
  filter(!is.na(PRACTICAS)) %>% 
  group_by(PRACTICAS) %>% 
  summarise(fi = n(), .groups = "drop") %>% 
  arrange(PRACTICAS) %>% 
  mutate(
    porcentaje = round(fi / sum(fi) * 100, 1)
  )

ggplot(df, aes(x = PRACTICAS, y = porcentaje)) +
  geom_point(shape = 18, color = "red") +
  geom_segment(aes(xend = PRACTICAS, yend = 0), size = 1, color = "blue") +
  labs(
    x = "Número de prácticas", 
    y = "Porcentaje (%)", 
    title = "Diagrama de bastones de la variable Prácticas"
  ) +
  theme_minimal() +
  geom_text(
    aes(label = paste0(porcentaje, "%")), 
    vjust = -0.5
  )

Ver código
library(dplyr)
library(ggplot2)

df <- tabla_final %>% 
  filter(PRACTICAS != "Total") %>% 
  mutate(
    PRACTICAS = as.numeric(PRACTICAS),
    Hi = as.numeric(Hi)
  ) %>% 
  arrange(PRACTICAS)

ggplot(df, aes(x = PRACTICAS, y = Hi)) +
  geom_step(size = 1.2) +
  geom_point(size = 3) +
  scale_x_continuous(breaks = df$PRACTICAS) +
  scale_y_continuous(limits = c(0, 1)) +
  labs(
    title = "Función de Distribución Acumulada (Prácticas)",
    x = "Número de prácticas",
    y = "Frecuencia relativa acumulada (Hi)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    panel.grid.minor = element_blank()
  )

La distribución acumulada de la variable prácticas muestra un comportamiento progresivo y ordenado, en el cual la frecuencia relativa acumulada (Hi) aumenta de manera escalonada conforme se incrementa el número de prácticas. Esto indica que la variable presenta una distribución discreta bien definida, sin saltos abruptos ni concentraciones extremas en un solo valor. A medida que aumentan las prácticas, se observa una acumulación constante de la proporción de sujetos, lo que sugiere una distribución relativamente equilibrada entre las diferentes categorías. La pendiente de la función permite identificar que no existe una dominancia marcada de valores bajos o altos, sino una dispersión moderada de los datos. En conjunto, la forma de la función de distribución acumulada refleja una tendencia estable, lo cual facilita la interpretación de percentiles y evidencia que la variable prácticas se comporta de manera consistente dentro de la muestra analizada.

4.4 Variable Continua

ImportanteLa Variable Continua se tabula con intervalos


- Generación de intervalos

Ver código
Min <- min(deporte$PESO)
Min
[1] 48
Ver código
Max <- max(deporte$PESO)
Max
[1] 80
Ver código
R <- Max - Min
R
[1] 32
Ver código
m <- ceiling(1 + 3.322 * log10(nrow(deporte)))
m
[1] 9
Ver código
A <- ceiling((R/m) * 1) / 1
A
[1] 4
Ver código
RC <- A * m
RC
[1] 36
PrecauciónLa amplitud debe tener tanto decimales como lo tienen los datos originales. Si tiene un decimal la fórmula se multiplica y se divide por 10. Si tiene dos decimales la fórmula se multiplica y se divide por 100 y así sucesivamente
Ver código
D <- RC - R
D
[1] 4
Ver código
Xmin <- Min - 4
Xmin
[1] 44
Ver código
Xmax <- Max + 4
Xmax
[1] 84
ImportanteLa diferencia se debe dividir en dos números lo más equitativos de tal manera que estos números tengan tantos decimales como los datos originales. Al mínimo se le resta uno de los números y al máximo se le suma el otro

Tabla No.4: Distribución de frecuencias de la edad de los sujetos

Ver código
# Crear intervalos
interv <- cut(
  x = deporte$PESO, 
  breaks = seq(Xmin, Xmax, by = A), 
  include.lowest = TRUE
)

# Marca de clase inicial
m1 <- (Xmin + (Xmin + A)) / 2

tabla_final <- tibble(Peso = interv) %>% 
  group_by(Peso) %>% 
  summarise(fi = n()) %>% 
  mutate(
    hi = round(fi/sum(fi), 4),
    Porcentaje = paste0(hi*100, "%"),
    mi = seq(m1, m1 + (n() - 1)*A, by = A),
    Fi = cumsum(fi),
    Hi = format(round(cumsum(hi), 4), nsmall = 3)
  ) %>% 
  mutate(
    Peso = as.character(Peso),
    mi = as.character(mi),
    Fi = as.character(Fi)
  ) %>% 
  relocate(Peso, mi, fi, hi, Porcentaje, Fi, Hi) %>% 
  bind_rows(
    tibble(
      Peso = "Total",
      mi = "",
      fi = sum(.$fi),
      hi = round(sum(.$hi), 4),
      Porcentaje = paste0(round(sum(.$hi)*100, 2), "%"),
      Fi = as.character(sum(.$fi)),
      Hi = format(1, nsmall = 3)
    )
  )

tabla_final %>% 
  knitr::kable(
    col.names = c("Peso", "mi", "fi", "hi", "Porcentaje", "Fi", "Hi"), 
    align = c("l", "c", "c", "c", "c", "c", "c")
  ) %>% 
  kableExtra::kable_styling(full_width = FALSE) %>% 
  kableExtra::row_spec(
    nrow(tabla_final), 
    color = "white", 
    background = "red",
    bold = TRUE
  ) %>% 
  kableExtra::add_header_above(
    c("Distribución de frecuencias del peso de los sujetos" = 7)
  )
Distribución de frecuencias del peso de los sujetos
Peso mi fi hi Porcentaje Fi Hi
[44,48] 46 6 0.030 3% 6 0.030
(48,52] 50 18 0.090 9% 24 0.120
(52,56] 54 22 0.110 11% 46 0.230
(56,60] 58 36 0.180 18% 82 0.410
(60,64] 62 24 0.120 12% 106 0.530
(64,68] 66 22 0.110 11% 128 0.640
(68,72] 70 33 0.165 16.5% 161 0.805
(72,76] 74 14 0.070 7% 175 0.875
(76,80] 78 25 0.125 12.5% 200 1.000
Total 200 1.000 100% 200 1.000
ImportanteNota

Aunque la regla de Sturges indicó 9 intervalos, el ajuste del rango y la amplitud generaron un intervalo adicional. Esto garantiza la cobertura completa de los datos.

Ver código
df <- tabla_final %>% 
  filter(Peso != "Total") %>% 
  mutate(
    mi = as.numeric(mi),
    fi = as.numeric(fi)
  )

ggplot(df, aes(x = mi, y = fi)) +
  geom_col(width = A, fill = "steelblue", color = "black") +
  labs(
    title = "Histograma del peso de los sujetos",
    x = "Peso",
    y = "Frecuencia"
  ) +
  theme_minimal()

Ver código
df <- tabla_final %>% 
  filter(Peso != "Total") %>% 
  mutate(
    # Extraer límite superior del intervalo
    ls = as.numeric(sub(".*,", "", gsub("\\[|\\]|\\(|\\)", "", Peso))),
    Hi = as.numeric(Hi)
  )

ggplot(df, aes(x = ls, y = Hi)) +
  geom_line(size = 1) +
  geom_point(size = 2) +
  labs(
    title = "Ojiva del peso de los sujetos",
    x = "Peso (límite superior del intervalo)",
    y = "Frecuencia acumulada relativa"
  ) +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()

Ver código
df <- tabla_final %>% 
  filter(Peso != "Total") %>% 
  mutate(
    mi = as.numeric(mi),
    fi = as.numeric(fi)
  )

# Expandir datos según frecuencia
peso_expandido <- df %>%
  slice(rep(1:n(), fi))

# Gráfico de densidad
ggplot(peso_expandido, aes(x = mi)) +
  geom_density(fill = "steelblue", alpha = 0.5, size = 1) +
  labs(
    title = "Densidad del peso de los sujetos",
    x = "Peso",
    y = "Densidad"
  ) +
  theme_minimal()

La distribución de frecuencias del peso muestra que los datos se concentran principalmente en los intervalos centrales, destacándose el rango de 56 a 60 kg como el de mayor frecuencia con un 18%, seguido por los intervalos de 68 a 72 kg con 16.5% y 76 a 80 kg con 12.5%, lo que indica una tendencia hacia valores medios-altos; la frecuencia acumulada evidencia que el 53% de los sujetos pesa hasta 64 kg y el 80.5% hasta 72 kg, sugiriendo una distribución ligeramente asimétrica hacia la derecha, mientras que los intervalos extremos presentan menores proporciones, lo que refleja menor presencia de valores muy bajos o muy altos, y en conjunto los datos muestran una dispersión moderada con concentración alrededor de los 58 a 70 kg.

4.5 Tablas de contingencia

Ver código
# Tabla de contingencia
tabla_GENERO_PESO <- table(deporte$GENERO, deporte$PESO)

# Convertir a data frame
tabla_df <- as.data.frame.matrix(tabla_GENERO_PESO)

# Totales
tabla_df$Total <- rowSums(tabla_df)
total_fi <- sum(tabla_df$Total)

# Fila total
tabla_df <- rbind(tabla_df, Total = c(colSums(tabla_GENERO_PESO), total_fi))

# Mostrar tabla
tabla_df %>%
  knitr::kable(
    col.names = c(colnames(tabla_df)),
    align = "c"
  ) %>%
  kableExtra::kable_styling(full_width = FALSE) %>%
  kableExtra::row_spec(
    nrow(tabla_df),
    bold = TRUE,
    color = "white",
    background = "red"
  )
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 Total
Femenino 3 2 1 0 3 1 3 2 4 4 5 2 8 4 1 2 1 1 3 5 3 4 1 9 2 1 6 1 0 4 1 2 4 93
Masculino 3 4 5 2 1 1 2 3 6 4 4 5 4 2 5 6 3 3 4 2 1 5 4 3 5 1 2 1 2 4 1 4 5 107
Total 6 6 6 2 4 2 5 5 10 8 9 7 12 6 6 8 4 4 7 7 4 9 5 12 7 2 8 2 2 8 2 6 9 200
Ver código
# Tabla de contingencia
tabla_GENERO_PESO <- table(deporte$GENERO, deporte$PESO)

# Convertir a data frame
tabla_df <- as.data.frame.matrix(tabla_GENERO_PESO)

# Total general
total_fi <- sum(tabla_df)

# Frecuencia relativa
tabla_df <- tabla_df / total_fi

# Totales
tabla_df$Total <- rowSums(tabla_df)
total_column <- colSums(tabla_df)

# Fila total
tabla_df <- rbind(tabla_df, Total = total_column)

# Mostrar tabla
tabla_df %>%
  knitr::kable(
    col.names = c(colnames(tabla_df)),
    align = "c"
  ) %>%
  kableExtra::kable_styling(full_width = FALSE) %>%
  kableExtra::row_spec(
    nrow(tabla_df),
    bold = TRUE,
    color = "white",
    background = "red"
  )
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 Total
Femenino 0.015 0.01 0.005 0.00 0.015 0.005 0.015 0.010 0.02 0.02 0.025 0.010 0.04 0.02 0.005 0.01 0.005 0.005 0.015 0.025 0.015 0.020 0.005 0.045 0.010 0.005 0.03 0.005 0.00 0.02 0.005 0.01 0.020 0.465
Masculino 0.015 0.02 0.025 0.01 0.005 0.005 0.010 0.015 0.03 0.02 0.020 0.025 0.02 0.01 0.025 0.03 0.015 0.015 0.020 0.010 0.005 0.025 0.020 0.015 0.025 0.005 0.01 0.005 0.01 0.02 0.005 0.02 0.025 0.535
Total 0.030 0.03 0.030 0.01 0.020 0.010 0.025 0.025 0.05 0.04 0.045 0.035 0.06 0.03 0.030 0.04 0.020 0.020 0.035 0.035 0.020 0.045 0.025 0.060 0.035 0.010 0.04 0.010 0.01 0.04 0.010 0.03 0.045 1.000
Ver código
data_porcentaje <- deporte %>%
  count(GENERO, PESO) %>%
  group_by(GENERO) %>%
  mutate(porcentaje = n / sum(n) * 100)

ggplot(data_porcentaje, aes(x = GENERO, y = porcentaje, fill = PESO)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(
    title = "Distribución porcentual del peso según género",
    x = "Género",
    y = "Porcentaje",
    fill = "Peso"
  ) +
  theme_minimal() +
  geom_text(aes(label = sprintf("%.1f%%", porcentaje)), 
            position = position_dodge(0.9), 
            vjust = -0.5, 
            size = 3)

Ver código
ggplot(data_porcentaje, aes(x = GENERO, y = porcentaje, fill = PESO)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(
    title = "Distribución porcentual del peso según género",
    x = "Género",
    y = "Porcentaje",
    fill = "Peso"
  ) +
  theme_minimal() +
  geom_text(aes(label = sprintf("%.1f%%", porcentaje)), 
            position = position_stack(vjust = 0.5), 
            color = "white",
            size = 3)

Ver código
ggplot(data_porcentaje, aes(x = PESO, y = porcentaje, fill = GENERO)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(
    title = "Distribución porcentual del género según peso",
    x = "Peso",
    y = "Porcentaje",
    fill = "Género"
  ) +
  theme_minimal() +
  geom_text(aes(label = sprintf("%.1f%%", porcentaje)), 
            position = position_stack(vjust = 0.5), 
            color = "white",
            size = 3) +
  coord_flip()

La distribución de frecuencias del peso según género evidencia un comportamiento relativamente equilibrado entre hombres y mujeres, con un total de 200 sujetos, de los cuales 93 corresponden al género femenino y 107 al masculino. Se observa que los valores de peso se concentran principalmente en el rango medio, especialmente entre 56 y 64 kg, donde se presentan las mayores frecuencias en ambos grupos, destacándose el valor de 60 kg como uno de los puntos de mayor concentración total. Asimismo, el género masculino presenta una ligera mayor dispersión hacia valores superiores, alcanzando frecuencias más constantes en rangos altos (por encima de 70 kg), mientras que el género femenino muestra una distribución más concentrada en intervalos medios. En los extremos inferiores y superiores de la distribución se evidencian menores frecuencias, lo que indica una baja presencia de individuos con pesos muy bajos o muy altos. En conjunto, la distribución sugiere una tendencia central bien definida con ligera asimetría hacia la derecha, especialmente influenciada por el comportamiento del grupo masculino, y una variabilidad moderada en ambos géneros.

Referencias

Wickham, Hadley, Mara Averick, Jennifer Bryan, et al. 2019. Welcome to the tidyverse. 4: 1686. https://doi.org/10.21105/joss.01686.
Wickham, Hadley, y Jennifer Bryan. 2025. readxl: Read Excel Files. https://doi.org/10.32614/CRAN.package.readxl.
William Revelle. 2026. psych: Procedures for Psychological, Psychometric, and Personality Research. https://CRAN.R-project.org/package=psych.
Zhu, Hao. 2024. kableExtra: Construct Complex Table with ’kable’ and Pipe Syntax. https://doi.org/10.32614/CRAN.package.kableExtra.