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
- Població i mostra
- Tipus de variables
- Mesures de tendència central: mitjana, mediana i moda
- Mesures de dispersió: rang, variància, desviació estàndard i IQR
- Mesures de posició: percentils i quartils
- Visualitzacions bàsiques: histograma i boxplot
- 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:
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.concatenateuneix 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 frequentMesures 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:
Punts importants del codi:
.var()i.std()de pandas fan servir per defecte la versió mostral (divideixen entre n−1, paràmetreddof=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:
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=50controla la granularitat: pocs bins amaguen detalls, massa bins generen soroll. Prova diversos valors.axvlinedibuixa 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.0La 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
- Què és el Machine Learning?
- Història i evolució del Machine Learning
- Tipus de Machine Learning
- Aplicacions del Machine Learning
- El flux de treball d'un projecte de Machine Learning
Mòdul 2: Fonaments d'Estadística i Probabilitat
- Conceptes bàsics d'estadística
- Distribucions de probabilitat
- Correlació i covariància
- Inferència estadística
- Teorema de Bayes
Mòdul 3: Preprocessament de Dades
- Neteja de dades
- Gestió de dades mancants
- Transformació de dades
- Codificació de variables categòriques
- Normalització i estandardització
- Enginyeria de característiques
Mòdul 4: Algorismes de Machine Learning Supervisat
- Regressió lineal
- Regressió logística
- Arbres de decisió
- Màquines de suport vectorial (SVM)
- K veïns més propers (K-NN)
- Naive Bayes
- Xarxes neuronals
Mòdul 5: Algorismes de Machine Learning No Supervisat
- Clustering: K-means
- Clustering jeràrquic
- Anàlisi de components principals (PCA)
- Anàlisi d'agrupament DBSCAN
- Visualització de dades amb t-SNE i UMAP
Mòdul 6: Avaluació i Validació de Models
- Divisió de dades: entrenament, validació i prova
- Mètriques d'avaluació
- Validació creuada
- Corba ROC i AUC
- Overfitting i underfitting
Mòdul 7: Tècniques Avançades i Optimització
- Regularització: Ridge, Lasso i Elastic Net
- Ensemble Learning
- Gradient Boosting
- Xarxes neuronals profundes (Deep Learning)
- Optimització d'hiperparàmetres
Mòdul 8: Implementació i Desplegament de Models
- Frameworks i biblioteques populars
- Implementació de models en producció
- Manteniment i monitoratge de models
- Consideracions ètiques i de privadesa
Mòdul 9: Projectes Pràctics
- Projecte 1: Predicció de preus d'habitatges
- Projecte 2: Classificació d'imatges
- Projecte 3: Anàlisi de sentiments a les xarxes socials
- Projecte 4: Detecció de fraus
- Projecte 5: Segmentació de clients
