competencies |>
count(habitat)# A tibble: 3 × 2
habitat n
<fct> <int>
1 Fins a 10000 101
2 De 10001 a 100000 212
3 Més de 100000 167
Estadística descriptiva
Centre d’Estudis d’Opinió
27 d’octubre del 2026
Treballarem amb les dades netes de l’exercici de la sessió 1: competencies (480 alumnes de 6è).
Abans de fer inferències o comparacions, cal conèixer bé què tenim.
| Tipus de variable | Exemples | Mesures | Gràfics |
|---|---|---|---|
| Nominal | Sexe, titularitat del centre | Freqüències, proporcions, moda | Gràfica de barres |
| Ordinal | Grau d’acord, mida del municipi | Freqüències, proporcions (i acumulades) | Barres ordenades |
| Quantitativa discreta | Nre. de fills, cursos fets | Mitjana, mediana, desviació… | Barres o histograma, boxplot |
| Quantitativa contínua | Edat, notes, ingressos | Mitjana, mediana, desviació, asimetria… | Histograma, boxplot |
El tipus de variable determina què podem fer i com ho podem interpretar.
# A tibble: 3 × 2
habitat n
<fct> <int>
1 Fins a 10000 101
2 De 10001 a 100000 212
3 Més de 100000 167
# A tibble: 3 × 4
habitat n percentatge percentatge_acumulat
<fct> <int> <dbl> <dbl>
1 Fins a 10000 101 21.0 21.0
2 De 10001 a 100000 212 44.2 65.2
3 Més de 100000 167 34.8 100
Com que habitat és un factor ordenat, la taula surt en l’ordre correcte i l’acumulat té sentit: el 65 % dels alumnes estudien en municipis de 100.000 habitants o menys.
Tendència central
Posició
Dispersió
Forma
Exemple: alçades ordenades: 165, 168, 170, 172, 210
mitjana <- mean(competencies$nota_ang, na.rm = TRUE)
mediana <- median(competencies$nota_ang, na.rm = TRUE)
ggplot(competencies, aes(x = nota_ang)) +
geom_histogram(binwidth = 5, boundary = 0, fill = bordeus_clar, color = "white") +
geom_vline(xintercept = mitjana, color = bordeus, linetype = "dashed", linewidth = 1) +
geom_vline(xintercept = mediana, color = gris_fosc, linetype = "dotted", linewidth = 1) +
annotate("text", x = mitjana - 1, y = Inf, vjust = 1.5, hjust = 1, color = bordeus,
label = paste("Mitjana:", round(mitjana, 1)), size = 5) +
annotate("text", x = mediana + 1, y = Inf, vjust = 1.5, hjust = 0, color = gris_fosc,
label = paste("Mediana:", round(mediana, 1)), size = 5) +
labs(x = "Puntuació d'anglès (0-100)", y = "Nombre d'alumnes")Les notes d’anglès tenen una cua a l’esquerra (alguns alumnes amb notes molt baixes): la mitjana queda per sota de la mediana.
count()Conèixer només la mitjana pot portar a interpretacions enganyoses.
Exemple: si la mitjana d’edat és 40 anys i la desviació típica és 5, la majoria de valors estan entre 35 i 45 anys.
set.seed(123)
dades_sd <- bind_rows(
tibble(valor = rnorm(10000, sd = 0.5), grup = "Desviació típica = 0,5"),
tibble(valor = rnorm(10000, sd = 1), grup = "Desviació típica = 1"),
tibble(valor = rnorm(10000, sd = 2), grup = "Desviació típica = 2")
) |>
mutate(grup = factor(grup, levels = unique(grup)))
ggplot(dades_sd, aes(x = valor)) +
geom_histogram(aes(y = after_stat(density)), bins = 60, fill = bordeus_clar, color = "white") +
geom_vline(xintercept = 0, color = bordeus, linetype = "dashed", linewidth = 1) +
facet_wrap(~ grup, ncol = 3) +
coord_cartesian(xlim = c(-5, 5)) +
labs(x = NULL, y = "Densitat")Normals amb mitjana 0 i diferent desviació típica
\[s = \sqrt{\frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2}\]
Alçades: 160, 170, 180, 165, 175 → \(\bar{x} = 170\)
| \(x_i\) | \(x_i - \bar{x}\) | \((x_i - \bar{x})^2\) |
|---|---|---|
| 160 | −10 | 100 |
| 170 | 0 | 0 |
| 180 | 10 | 100 |
| 165 | −5 | 25 |
| 175 | 5 | 25 |
| Suma | 0 | 250 |
\[s = \sqrt{\frac{250}{5 - 1}} = \sqrt{62{,}5} \approx 7{,}91\]
R divideix per \(n-1\) (desviació mostral), que és el que fem servir quan les dades són una mostra. Si fossin tota la població, dividiríem per \(n\): \(\sqrt{250/5} \approx 7{,}07\).
summary() Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
18.20 64.90 77.75 74.52 85.70 100.00 16
O diverses mesures alhora, a la nostra manera:
# A tibble: 1 × 5
mitjana mediana desv_tipica iqr n
<dbl> <dbl> <dbl> <dbl> <int>
1 74.5 77.8 15.7 20.8 480
summarise() resumeix moltes files en una sola. Hi tornarem a la sessió 3 per comparar grups.
Com ho detectem? Mirant la forma de la distribució:
I, sobretot, fent un gràfic!
\[\text{Asimetria} = \frac{1}{n} \sum \left(\frac{x_i - \bar{x}}{s}\right)^3\]
set.seed(123)
n <- 10000
dades_asim <- bind_rows(
tibble(valor = as.numeric(scale(rnorm(n))), grup = "Simètrica"),
tibble(valor = as.numeric(scale(rlnorm(n, sdlog = 0.5))), grup = "Asimetria positiva"),
tibble(valor = as.numeric(scale(-rlnorm(n, sdlog = 0.5))), grup = "Asimetria negativa")
) |>
mutate(grup = factor(grup, levels = unique(grup)))
ggplot(dades_asim, aes(x = valor)) +
geom_histogram(aes(y = after_stat(density)), bins = 40, fill = bordeus_clar, color = "white") +
facet_wrap(~ grup, ncol = 1) +
coord_cartesian(xlim = c(-3, 3)) +
labs(x = NULL, y = NULL) +
theme(axis.text.y = element_blank())\[\text{Curtosi} = \frac{1}{n} \sum \left(\frac{x_i - \bar{x}}{s}\right)^4\]
Sovint es dona la curtosi centrada (curtosi − 3), per comparar-la directament amb la normal.
set.seed(123)
n <- 100000
dades_curt <- bind_rows(
tibble(valor = as.numeric(scale(runif(n))), grup = "Curtosi baixa (plana)"),
tibble(valor = as.numeric(scale(rnorm(n))), grup = "Curtosi normal"),
tibble(valor = as.numeric(scale(rt(n, df = 5))), grup = "Curtosi alta (cues llargues)")
) |>
mutate(grup = factor(grup, levels = unique(grup)))
ggplot(dades_curt, aes(x = valor)) +
geom_histogram(aes(y = after_stat(density)), bins = 60, fill = bordeus_clar, color = "white") +
facet_wrap(~ grup, ncol = 1) +
coord_cartesian(xlim = c(-4, 4)) +
labs(x = NULL, y = NULL) +
theme(axis.text.y = element_blank())L’objectiu d’un gràfic és comunicar la informació de forma clara i intuïtiva.
ggplot2Un gràfic de ggplot2 es construeix per capes, unides amb +:
| Gràfic | Geometria |
|---|---|
| Barres | geom_bar() |
| Histograma | geom_histogram() |
| Diagrama de caixa | geom_boxplot() |
| Violí | geom_violin() |
Atenció: entre capes de ggplot es fa servir +, no |>.
set.seed(12345)
x_bins <- rnorm(1000)
nivells <- c("6 intervals", "25 intervals", "150 intervals")
d6 <- tibble(valor = x_bins, bins = factor("6 intervals", levels = nivells))
d25 <- tibble(valor = x_bins, bins = factor("25 intervals", levels = nivells))
d150 <- tibble(valor = x_bins, bins = factor("150 intervals", levels = nivells))
corba <- tibble(valor = rep(seq(-3, 3, length.out = 200), 3),
bins = factor(rep(nivells, each = 200), levels = nivells),
densitat = dnorm(valor))
ggplot(mapping = aes(x = valor, y = after_stat(density))) +
geom_histogram(data = d6, bins = 6, fill = bordeus_clar, color = NA) +
geom_histogram(data = d25, bins = 25, fill = bordeus_clar, color = NA) +
geom_histogram(data = d150, bins = 150, fill = bordeus_clar, color = NA) +
geom_line(data = corba, aes(x = valor, y = densitat), color = bordeus, linewidth = 1) +
facet_wrap(~ bins, ncol = 3) +
coord_cartesian(xlim = c(-3, 3)) +
labs(x = NULL, y = "Densitat")Les mateixes 1.000 dades amb 6, 25 i 150 intervals. La línia és la distribució real.
Representa
Detecta asimetria, dispersió i valors atípics
set.seed(123)
xb <- c(rnorm(99), 3.5)
q <- quantile(xb, c(0.25, 0.5, 0.75)); iqr <- q[3] - q[1]
bigoti_sup <- max(xb[xb <= q[3] + 1.5 * iqr]); bigoti_inf <- min(xb[xb >= q[1] - 1.5 * iqr])
ggplot(tibble(valor = xb), aes(x = 0, y = valor)) +
geom_boxplot(fill = bordeus_clar, width = 0.5, outlier.size = 3) +
annotate("text", x = 0.3, y = c(q, bigoti_sup, bigoti_inf, 3.5),
label = c("Q1", "Mediana", "Q3", "Bigoti superior", "Bigoti inferior", "Outlier"),
hjust = 0, size = 5) +
annotate("segment", x = -0.33, xend = -0.33, y = q[1], yend = q[3],
arrow = arrow(ends = "both", length = unit(0.1, "in"))) +
annotate("text", x = -0.37, y = q[2], label = "IQR", angle = 90, size = 5) +
coord_cartesian(xlim = c(-0.5, 0.8)) +
labs(x = NULL, y = NULL) +
theme(axis.text = element_blank(), panel.grid = element_blank())set.seed(123)
nb <- 200
bind_rows(
tibble(valor = rnorm(nb, sd = 0.5), tipus = "Dispersió baixa", grup = "Dispersió"),
tibble(valor = rnorm(nb, sd = 2), tipus = "Dispersió alta", grup = "Dispersió"),
tibble(valor = as.numeric(scale(rlnorm(nb, sdlog = 0.7))), tipus = "Asim. positiva", grup = "Asimetria"),
tibble(valor = as.numeric(scale(-rlnorm(nb, sdlog = 0.7))), tipus = "Asim. negativa", grup = "Asimetria"),
tibble(valor = as.numeric(scale(runif(nb))), tipus = "Curtosi baixa", grup = "Curtosi"),
tibble(valor = as.numeric(scale(rt(nb, df = 2))), tipus = "Curtosi alta", grup = "Curtosi")
) |>
mutate(tipus = factor(tipus, levels = unique(tipus)),
grup = factor(grup, levels = unique(grup))) |>
ggplot(aes(x = tipus, y = valor)) +
geom_boxplot(fill = bordeus_clar, width = 0.6) +
facet_wrap(~ grup, scales = "free_x") +
labs(x = NULL, y = NULL)El violí mostra la densitat; el boxplot del mig, el resum numèric.
Objectiu: fer una descripció completa de dues variables de competencies_basiques_net.csv (les dades que vau netejar a la sessió 1).
1. Variable categòrica: habitat
habitat en factor ordenatcount() + mutate()geom_bar()2. Variable numèrica: nota_cat
summary(), sd(), IQR(), quantile()geom_histogram(), geom_boxplot()Comenteu els resultats en tot moment (amb # a l’script)!
Introducció a l’estadística amb R · Estadística descriptiva