Al final del mòdul anterior vam deixar el flux de treball d'un projecte de Machine Learning a la porta de la fase d'exploració: abans d'entrenar cap model cal entendre les dades. L'estadística descriptiva és precisament això: el conjunt d'eines que resumeix milers de files en uns quants nombres i gràfics amb significat. En aquesta lliçó aprendràs a distingir població i mostra, a classificar tipus de variables i a calcular i interpretar les mesures de tendència central, dispersió i posició, aplicant-ho tot a les dades de comandes de MercaFresh amb pandas i matplotlib.

Contingut

  1. Població i mostra
  2. Tipus de variables
  3. Mesures de tendència central: mitjana, mediana i moda
  4. Mesures de dispersió: rang, variància, desviació estàndard i IQR
  5. Mesures de posició: percentils i quartils
  6. Visualitzacions bàsiques: histograma i boxplot
  7. Cas pràctic complet: comandes de MercaFresh

Població i mostra

  • Població: el conjunt complet d'elements que volem estudiar. Per a MercaFresh, totes les comandes fetes al llarg de la seva història (o totes les que es faran).
  • Mostra: un subconjunt de la població que sí que tenim a mà. Per exemple, les 10.000 comandes de l'últim trimestre.

A la pràctica gairebé mai no treballem amb la població completa: o és inabastable, o inclou dades futures que encara no existeixen. Per això calculem estadístics sobre la mostra i els fem servir com a aproximació dels paràmetres de la població.

Concepte Població Mostra
Símbol de la mida N n
Mitjana μ (mu) x̄ (x barra)
Desviació estàndard σ (sigma) s
Es coneix a la pràctica? Gairebé mai Sí, es calcula de les dades

Aquesta distinció pot semblar un tecnicisme ara mateix, però és la base de la inferència estadística que veurem a la lliçó 02-04: allà aprendrem a quantificar fins a quin punt ens podem refiar d'una mostra per parlar de la població.

En Machine Learning la idea reapareix amb un altre nom: el conjunt d'entrenament és una mostra de totes les dades possibles, i volem que el model generalitzi a la població (les dades futures).

Tipus de variables

Cada columna d'un dataset és una variable, i el seu tipus determina quines operacions i quins gràfics tenen sentit.

graph TD
    V[Variable] --> N[Numerica]
    V --> C[Categorica]
    N --> NC["Continua<br>(import de la comanda: 47,35 EUR)"]
    N --> ND["Discreta<br>(articles per comanda: 1, 2, 3...)"]
    C --> CN["Nominal<br>(provincia: Barcelona, Valencia...)"]
    C --> CO["Ordinal<br>(satisfaccio: baixa < mitjana < alta)"]
  • Numèrica contínua: pot prendre qualsevol valor dins d'un rang. Exemple MercaFresh: import de la comanda (47,35 €), temps de lliurament (38,2 minuts).
  • Numèrica discreta: només valors enters comptables. Exemple: nombre d'articles per comanda, nombre de comandes per client al mes.
  • Categòrica nominal: categories sense ordre. Exemple: província de lliurament, mètode de pagament (targeta, paypal, contra_reemborsament).
  • Categòrica ordinal: categories amb ordre però sense una distància definida entre elles. Exemple: valoració del client (baixa < mitjana < alta), franja horària preferent.

Un parany habitual: que una cosa estigui codificada amb nombres no la fa numèrica. El codi postal 08001 és una variable nominal; calcular-ne la mitjana no vol dir res. Al mòdul 3 (lliçó 03-04) veurem com convertir variables categòriques a nombres de manera correcta per als models.

Mesures de tendència central: mitjana, mediana i moda

Responen a la pregunta: quin és el valor "típic"?

  • Mitjana aritmètica (x̄): suma dels valors dividida per n. Fa servir tota la informació, però és sensible als valors extrems.
  • Mediana: el valor central quan ordenem les dades (si n és parell, la mitjana dels dos centrals). Robusta davant dels extrems.
  • Moda: el valor més freqüent. És l'única de les tres que té sentit per a variables categòriques.

Vegem-ho amb dades fictícies de MercaFresh:

import numpy as np
import pandas as pd

# Llavor perque els resultats siguin reproduibles
rng = np.random.default_rng(42)

# Simulem 1.000 comandes: la majoria entre 20 i 80 EUR,
# mes 15 comandes enormes de clients d'empresa (hostaleria)
imports_comanda = np.concatenate([
    rng.gamma(shape=4.0, scale=12.0, size=985),  # comandes domestiques
    rng.uniform(400, 900, size=15)               # comandes d'hostaleria
])

comandes = pd.DataFrame({"import_comanda": imports_comanda.round(2)})

print("Mitjana: ", comandes["import_comanda"].mean().round(2))
print("Mediana: ", comandes["import_comanda"].median().round(2))

Sortida aproximada:

Mitjana:  54.79
Mediana:  44.87

Explicació detallada del codi:

  • np.random.default_rng(42) crea un generador de nombres aleatoris amb llavor fixa: cada execució produeix les mateixes dades, essencial per poder reproduir anàlisis.
  • rng.gamma(...) genera imports amb una forma realista (moltes comandes mitjanes, cua de comandes grans); no cal que entenguis aquesta distribució encara, la veurem a la lliçó 02-02.
  • np.concatenate uneix les comandes domèstiques amb 15 comandes atípiques d'empresa.
  • .mean() i .median() són mètodes de pandas que calculen mitjana i mediana ignorant els valors nuls si n'hi hagués.

Fixa't en el resultat: la mitjana (≈55 €) és clarament més gran que la mediana (≈45 €). Aquestes 15 comandes d'hostaleria "estiren" la mitjana cap amunt, però gairebé no mouen la mediana. Si MercaFresh digués "la nostra comanda típica és de 55 €" estaria exagerant: la meitat de les comandes no arriba als 45 €.

Mesura Avantatge Inconvenient Quan preferir-la
Mitjana Fa servir totes les dades; bones propietats matemàtiques Sensible als valors extrems Dades simètriques sense outliers
Mediana Robusta davant dels extrems Ignora la magnitud dels valors Dades asimètriques (imports, salaris, temps)
Moda Serveix per a categòriques Pot no ser única o no existir Variables categòriques; dades discretes

La moda amb una variable categòrica:

metodes = pd.Series(["targeta"] * 620 + ["paypal"] * 290 + ["contra_reemborsament"] * 90)
print(metodes.mode()[0])   # targeta  -> el metode de pagament mes frequent

Mesures de dispersió: rang, variància, desviació estàndard i IQR

Dos supermercats poden tenir el mateix import mitjà de comanda i comportaments totalment diferents: un amb comandes sempre al voltant dels 50 €, un altre amb comandes de 5 € i de 500 €. La dispersió mesura aquesta variabilitat.

  • Rang: màxim − mínim. Simple però fràgil: depèn només de dos valors.
  • Variància (s²): mitjana de les desviacions al quadrat respecte de la mitjana. Les seves unitats són les unitats originals al quadrat (euros²!), cosa que en dificulta la interpretació.
  • Desviació estàndard (s): arrel quadrada de la variància. Torna a les unitats originals: "els imports es desvien típicament uns 30 € de la mitjana".
  • Rang interquartílic (IQR): Q3 − Q1, l'amplada del 50 % central de les dades. Robust davant dels valors extrems, igual que la mediana.
serie = comandes["import_comanda"]

print("Rang:                ", (serie.max() - serie.min()).round(2))
print("Variancia:           ", serie.var().round(2))
print("Desviacio estandard: ", serie.std().round(2))

q1 = serie.quantile(0.25)
q3 = serie.quantile(0.75)
print("IQR:                 ", (q3 - q1).round(2))

Sortida aproximada:

Rang:                 885.05
Variancia:            5090.71
Desviacio estandard:  71.35
IQR:                  35.09

Punts importants del codi:

  • .var() i .std() de pandas fan servir per defecte la versió mostral (divideixen entre n−1, paràmetre ddof=1). NumPy (np.var, np.std) usa per defecte la poblacional (divideix entre n, ddof=0). Amb 1.000 dades la diferència és minúscula, però convé saber que existeix.
  • .quantile(0.25) retorna el valor per sota del qual queda el 25 % de les dades (el primer quartil, Q1).

Observa el contrast: la desviació estàndard (≈71 €) està inflada per les comandes d'hostaleria, mentre que l'IQR (≈35 €) descriu millor la variabilitat de la comanda domèstica típica. Regla pràctica: mitjana + desviació estàndard per a dades simètriques, mediana + IQR per a dades asimètriques o amb outliers.

Mesures de posició: percentils i quartils

El percentil p és el valor per sota del qual queda el p % de les dades. Els quartils són tres percentils especials: Q1 (percentil 25), Q2 (percentil 50 = mediana) i Q3 (percentil 75).

Exemple amb temps de lliurament de MercaFresh:

# Temps de lliurament en minuts: la majoria ronden els 35-40 min,
# amb alguns repartiments lents per culpa del transit
lliuraments = pd.Series(rng.gamma(shape=9.0, scale=4.5, size=1000).round(1),
                        name="minuts")

percentils = lliuraments.quantile([0.25, 0.50, 0.75, 0.90, 0.95, 0.99])
print(percentils.round(1))

Sortida aproximada:

0.25    30.7
0.50    38.5
0.75    47.9
0.90    57.9
0.95    63.7
0.99    75.7

Lectura de negoci directa: la meitat de les comandes arriba en menys de 39 minuts, però el 5 % més lent supera els 64. Si MercaFresh promet "lliurament en menys de 60 minuts", el percentil 90 (≈58 min) diu que va justa: aproximadament 1 de cada 10 lliuraments frega o incompleix la promesa. Els percentils alts (p95, p99) són l'estàndard en logística i en enginyeria per vigilar els pitjors casos, no el cas mitjà.

Visualitzacions bàsiques: histograma i boxplot

Els nombres resumeixen; els gràfics revelen la forma de les dades.

Histograma

Divideix el rang de valors en intervals (bins) i compta quantes observacions cauen a cadascun.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(comandes["import_comanda"], bins=50, color="steelblue", edgecolor="white")
ax.axvline(comandes["import_comanda"].mean(), color="red", linestyle="--", label="Mitjana")
ax.axvline(comandes["import_comanda"].median(), color="green", linestyle="--", label="Mediana")
ax.set_xlabel("Import de la comanda (EUR)")
ax.set_ylabel("Nombre de comandes")
ax.set_title("Distribucio d'imports de comanda a MercaFresh")
ax.legend()
plt.tight_layout()
plt.show()
  • bins=50 controla la granularitat: pocs bins amaguen detalls, massa bins generen soroll. Prova diversos valors.
  • axvline dibuixa línies verticals per comparar visualment mitjana i mediana: en una distribució amb cua a la dreta com aquesta, la mitjana queda a la dreta de la mediana.

L'histograma mostrarà una massa principal de comandes entre 20 i 100 € amb una cua dreta llarga (les comandes d'hostaleria). Aquesta asimetria és l'explicació visual de per què mitjana i mediana difereixen.

Boxplot (diagrama de caixa)

Resumeix en un sol dibuix la mediana, els quartils i els valors atípics:

  • La caixa va de Q1 a Q3 (la seva alçada és l'IQR) amb una línia a la mediana.
  • Els bigotis s'estenen fins a l'última dada dins d'1,5 × IQR des de la caixa.
  • Els punts fora dels bigotis es marquen com a outliers (candidats a valors atípics, no culpables automàtics).
fig, ax = plt.subplots(figsize=(8, 3))
ax.boxplot(comandes["import_comanda"], vert=False)
ax.set_xlabel("Import de la comanda (EUR)")
ax.set_title("Boxplot d'imports: les comandes d'hostaleria apareixen com a outliers")
plt.tight_layout()
plt.show()

En aquest boxplot les 15 comandes d'hostaleria apareixeran com a punts aïllats a la dreta. Detectar-les és el primer pas; decidir què fer-ne (són errors? clients legítims d'un altre segment?) pertany a la neteja de dades del mòdul 3 (lliçó 03-01) i a la detecció d'anomalies que tractarem més endavant.

Cas pràctic complet: comandes de MercaFresh

Ajuntem-ho tot en el flux típic d'una primera exploració:

comandes_full = pd.DataFrame({
    "import_comanda": comandes["import_comanda"],
    "minuts_lliurament": lliuraments,
    "n_articles": rng.poisson(lam=12, size=1000),        # discreta
    "metode_pagament": rng.choice(["targeta", "paypal", "contra_reemborsament"],
                                  size=1000, p=[0.62, 0.29, 0.09])  # nominal
})

# describe() calcula de cop: n, mitjana, std, minim, quartils i maxim
print(comandes_full[["import_comanda", "minuts_lliurament", "n_articles"]].describe().round(2))

# Per a la variable categorica: frequencies, no mitjanes
print(comandes_full["metode_pagament"].value_counts(normalize=True).round(3))
  • describe() és la navalla suïssa de l'exploració: una taula amb gairebé totes les mesures d'aquesta lliçó.
  • value_counts(normalize=True) dona proporcions en lloc de recomptes; és el resum natural d'una variable nominal.

Amb aquesta taula, l'equip de MercaFresh ja pot respondre preguntes de negoci ("quina és la comanda típica?", "complim la promesa de lliurament?") sense haver entrenat cap model.

Errors Comuns i Consells

  • Fer servir la mitjana amb dades asimètriques o amb outliers. Imports, temps i salaris gairebé sempre tenen cua dreta: reporta també la mediana, o només la mediana.
  • Calcular mitjanes de variables categòriques codificades com a nombres (codis postals, IDs de producte). Comprova el significat de la columna, no només el seu dtype.
  • Confondre variància i desviació estàndard en interpretar. La variància és en unitats al quadrat; per comunicar resultats fes servir sempre la desviació estàndard.
  • Oblidar el paràmetre ddof: pandas fa servir n−1 i NumPy fa servir n per defecte. Si barreges llibreries i els nombres "no quadren", aquest sol ser el motiu.
  • Eliminar outliers a cegues. Un punt fora dels bigotis del boxplot és un candidat a revisió, no un error garantit: les comandes d'hostaleria de MercaFresh són diners de debò.
  • Consell: dibuixa sempre un histograma abans de decidir quins estadístics reportar. Dos datasets poden compartir mitjana i desviació estàndard i tenir formes radicalment diferents.

Exercicis

Exercici 1

Els temps de lliurament (en minuts) de 9 comandes d'una tarda són: [32, 35, 29, 41, 38, 33, 36, 95, 34]. Calcula a mà (i comprova-ho amb pandas) la mitjana i la mediana. Quina representa millor el lliurament "típic" i per què?

Exercici 2

Classifica aquestes variables de MercaFresh segons el seu tipus (numèrica contínua/discreta, categòrica nominal/ordinal): (a) pes total de la comanda en kg, (b) nombre de productes frescos a la comanda, (c) tipus de client (particular, empresa), (d) nivell del programa de fidelitat (bronze, plata, or), (e) codi postal de lliurament.

Exercici 3

Amb el DataFrame comandes_full del cas pràctic, calcula l'IQR de minuts_lliurament i determina els límits d'outliers segons la regla 1,5 × IQR (inferior: Q1 − 1,5·IQR; superior: Q3 + 1,5·IQR). Quantes comandes queden fora?

Solucions

Solució 1

import pandas as pd
temps = pd.Series([32, 35, 29, 41, 38, 33, 36, 95, 34])
print(temps.mean().round(2))   # 41.44
print(temps.median())          # 35.0

La mitjana (41,4 min) està distorsionada pel lliurament de 95 minuts (potser una incidència de trànsit). La mediana (35 min) representa millor el lliurament típic: 8 de les 9 comandes van arribar en menys de 41 minuts. Amb poques dades i un valor extrem, la mediana és l'elecció robusta.

Solució 2

  • (a) Pes en kg → numèrica contínua (pot ser 7,35 kg).
  • (b) Nombre de productes frescos → numèrica discreta (0, 1, 2...).
  • (c) Tipus de client → categòrica nominal (no hi ha ordre entre particular i empresa).
  • (d) Nivell de fidelitat → categòrica ordinal (bronze < plata < or).
  • (e) Codi postal → categòrica nominal, encara que s'escrigui amb dígits: ni l'ordre ni l'aritmètica entre codis tenen significat.

Solució 3

q1 = comandes_full["minuts_lliurament"].quantile(0.25)
q3 = comandes_full["minuts_lliurament"].quantile(0.75)
iqr = q3 - q1
lim_inf = q1 - 1.5 * iqr
lim_sup = q3 + 1.5 * iqr
outliers = comandes_full[(comandes_full["minuts_lliurament"] < lim_inf) |
                         (comandes_full["minuts_lliurament"] > lim_sup)]
print(f"Limits: [{lim_inf:.1f}, {lim_sup:.1f}] -> {len(outliers)} outliers")

Amb les dades simulades obtindràs al voltant de 5-15 outliers, tots per sobre del límit superior (lliuraments anormalment lents): exactament els punts que el boxplot dibuixa fora del bigoti dret. El límit inferior sortirà positiu però per sota del mínim real, així que no hi haurà outliers per sota.

Conclusió

En aquesta lliçó has construït el vocabulari bàsic de l'exploració de dades: la diferència entre població i mostra, els tipus de variables i les tres famílies de mesures (tendència central, dispersió i posició), juntament amb l'histograma i el boxplot per veure la forma de les dades. Has comprovat amb les comandes de MercaFresh que triar entre mitjana/desviació estàndard i mediana/IQR no és una qüestió cosmètica: canvia les conclusions de negoci. Precisament aquesta "forma" de les dades que revela l'histograma té nom i cognoms matemàtics: a la propera lliçó estudiarem les distribucions de probabilitat, els models teòrics (Bernoulli, binomial, Poisson, normal...) que descriuen com es generen dades com els imports i temps que acabem d'explorar.

Curs de Machine Learning

Mòdul 1: Introducció al Machine Learning

Mòdul 2: Fonaments d'Estadística i Probabilitat

Mòdul 3: Preprocessament de Dades

Mòdul 4: Algorismes de Machine Learning Supervisat

Mòdul 5: Algorismes de Machine Learning No Supervisat

Mòdul 6: Avaluació i Validació de Models

Mòdul 7: Tècniques Avançades i Optimització

Mòdul 8: Implementació i Desplegament de Models

Mòdul 9: Projectes Pràctics

Mòdul 10: Recursos Addicionals

© Copyright 2026. Tots els drets reservats