Últim projecte, i tornem a casa. Després d'habitatges, imatges, sentiments i frau, tanquem el cercle allà on va començar tot: MercaFresh. L'encàrrec és el clàssic de l'aprenentatge no supervisat: sense cap etiqueta, descobrir quins segments naturals de clients existeixen, posar-los nom de negoci, proposar una acció per a cadascun i deixar el sistema a punt per a producció. Practicaràs de cap a cap el mòdul 5 complet — K-means, jeràrquic, DBSCAN, PCA i t-SNE — sobre un dataset sintètic però realista de ~2.000 clients generat al mateix codi, construint les features RFM i els ratios que vas aprendre a 03-06 "Enginyeria de característiques". I com que és el projecte que tanca el mòdul, acabarem amb una recapitulació dels cinc projectes i el pont cap al mòdul 10.
Contingut
- Definició del problema: què és "èxit" sense etiquetes?
- Generació del dataset de clients
- De comandes a features: RFM i ratios
- EDA i escalat
- K-means: triar k amb colze i silhouette
- Contrast: clustering jeràrquic i DBSCAN
- Visualització: PCA i t-SNE
- Perfilat: de centroides a noms de negoci
- Accions per segment i com mesurar-les
- Dels segments a producció
- Recapitulació del mòdul 9
Definició del problema: què és "èxit" sense etiquetes?
Als projectes 1–4 hi havia una veritat contra la qual mesurar-se. Aquí no: ningú no sap quants segments hi ha "de debò". L'èxit es defineix diferent, com vas aprendre al mòdul 5:
- Validesa interna: clústers compactes i separats (silhouette, 05-01).
- Estabilitat: els segments no han de canviar radicalment amb una altra llavor o una altra mostra.
- Accionabilitat: cada segment ha de poder descriure's en una frase i associar-se a una acció de màrqueting diferent. Un clustering estadísticament perfecte però inexplicable a negoci és un fracàs.
Objectiu concret: entre 3 i 8 segments (menys no discrimina, més no es gestiona), perfilats i amb pla d'acció.
Generació del dataset de clients
Simulem l'històric de comandes de ~2.000 clients amb arquetips de comportament barrejats i soroll — així després podrem jutjar si els algorismes els redescobreixen. A la realitat, aquesta taula sortiria d'una consulta SQL a l'històric de comandes:
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
n = 2000
# Arquetips latents (proporcions): VIP, habitual, ocasional, adormit, nou
arquetip = rng.choice(5, size=n, p=[0.08, 0.32, 0.30, 0.20, 0.10])
# Parametres per arquetip: (recencia_mitjana_dies, comandes_any, tiquet_mitja)
params = {
0: (7, 90, 85), # VIP: compra setmanal, cistell gran
1: (12, 45, 45), # habitual: quinzenal, cistell mitja
2: (35, 12, 30), # ocasional
3: (160, 4, 38), # adormit: fa mesos que no compra
4: (10, 3, 25), # nou: recent pero amb poca historia
}
files = []
for a in arquetip:
r_mu, f_mu, m_mu = params[a]
recencia = max(1, rng.gamma(2, r_mu / 2))
comandes = max(1, rng.poisson(f_mu))
tiquet = max(8, rng.normal(m_mu, m_mu * 0.3))
frescos = np.clip(rng.normal([0.55, 0.45, 0.30, 0.35, 0.40][a], 0.12), 0, 1)
antiguitat = (rng.uniform(15, 90) if a == 4
else rng.uniform(180, 1400))
files.append([recencia, comandes, tiquet, frescos, antiguitat])
clients = pd.DataFrame(
files, columns=["recencia_dies", "comandes_12m", "tiquet_mitja_eur",
"pct_frescos", "antiguitat_dies"]
)
print(clients.describe().round(1))Nota honesta: coneixem els arquetips perquè els hem sembrat, però no els donarem a cap algorisme — són aquí només perquè tu, al final, puguis comparar allò descobert amb allò sembrat. El clustering treballarà a cegues, com a la realitat.
De comandes a features: RFM i ratios
Sobre les columnes base construïm el vector de segmentació, reeditant el RFM de 03-06:
X = pd.DataFrame({
"recencia": clients["recencia_dies"], # R
"frequencia": clients["comandes_12m"], # F
"monetari": clients["comandes_12m"] * clients["tiquet_mitja_eur"], # M anual
"tiquet_mitja": clients["tiquet_mitja_eur"],
"pct_frescos": clients["pct_frescos"],
"comandes_per_mes_actiu": clients["comandes_12m"]
/ (clients["antiguitat_dies"] / 30).clip(lower=1),
})L'últim ratio és enginyeria amb intenció: un client amb 3 comandes i 20 anys d'antiguitat no és el mateix que un amb 3 comandes i 3 setmanes — el ratio d'intensitat els separa, distingint els nous prometedors dels ocasionals crònics.
EDA i escalat
import matplotlib.pyplot as plt
X.hist(bins=40, figsize=(12, 6)); plt.tight_layout(); plt.show()
print(X.corr().round(2))Hi veuràs asimetries fortes a recencia, frequencia i monetari (cues a la dreta, el patró de 03-03 "Transformació de dades") — els apliquem log perquè els clústers no els dominin uns pocs extrems — i després estandarditzem, perquè K-means mesura distàncies euclidianes i sense escalar manaria la variable de més magnitud (monetari, en centenars d'euros), com vas aprendre a 03-05 i vas patir a 05-01:
from sklearn.preprocessing import StandardScaler
X_t = X.copy()
for col in ["recencia", "frequencia", "monetari"]:
X_t[col] = np.log1p(X_t[col])
esc = StandardScaler()
X_esc = esc.fit_transform(X_t)K-means: triar k amb colze i silhouette
El protocol de 05-01 "Clustering: K-means", complet:
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
inercies, siluetes = [], []
ks = range(2, 11)
for k in ks:
km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X_esc)
inercies.append(km.inertia_)
siluetes.append(silhouette_score(X_esc, km.labels_))
fig, eixos = plt.subplots(1, 2, figsize=(12, 4))
eixos[0].plot(ks, inercies, "o-"); eixos[0].set_title("Colze (inercia)")
eixos[1].plot(ks, siluetes, "o-"); eixos[1].set_title("Silhouette mitja")
for e in eixos: e.set_xlabel("k")
plt.show()Amb aquestes dades, el colze es doblega cap a k = 4–5 i la silhouette sol fer un màxim local a k = 5 (≈ 0,30–0,40; en dades reals de clients, valors així són normals — els segments humans no són esferes nítides). Triem k = 5, i n'anotem l'argument: coincideix el colze, silhouette raonable i un nombre gestionable per a màrqueting. La decisió de k sempre és meitat mètrica, meitat negoci.
km = KMeans(n_clusters=5, n_init=10, random_state=42).fit(X_esc)
clients["segment"] = km.labels_
print(clients["segment"].value_counts().sort_index())Contrast: clustering jeràrquic i DBSCAN
Un sol algorisme és una sola opinió. El jeràrquic de 05-02 aporta el dendrograma — la foto de com s'agrupen els clients a totes les escales:
from scipy.cluster.hierarchy import linkage, dendrogram, fcluster
enllac = linkage(X_esc, method="ward")
plt.figure(figsize=(11, 4))
dendrogram(enllac, truncate_mode="lastp", p=30, no_labels=True)
plt.title("Dendrograma (Ward, truncat)"); plt.ylabel("Distancia")
plt.show()
jer = fcluster(enllac, t=5, criterion="maxclust")
print(pd.crosstab(clients["segment"], jer))Si el dendrograma mostra 4–5 branques gruixudes i la taula creuada revela que els clústers jeràrquics coincideixen en gran mesura amb els de K-means, tenim convergència d'evidència: l'estructura és real, no un artefacte de l'algorisme.
DBSCAN (05-04) respon una altra pregunta: hi ha clients que no pertanyen a cap grup?
from sklearn.cluster import DBSCAN
db = DBSCAN(eps=0.9, min_samples=10).fit(X_esc)
print(pd.Series(db.labels_).value_counts().head())
print("Clients-soroll:", (db.labels_ == -1).sum())Els etiquetats com a −1 són clients-soroll: combinacions rares (tiquet enorme amb freqüència mínima, per exemple) que no encaixen en cap segment. K-means els hauria forçat dins del centroide més proper, contaminant-ne el perfil. A la pràctica convé revisar-los a part: alguns són errors de dades (03-01), d'altres són oportunitats singulars — comptes d'empresa, per exemple. Ajusta eps amb criteri: massa petit i tot és soroll; massa gran i tot és un únic clúster.
Visualització: PCA i t-SNE
Sis dimensions no es dibuixen; les projectem amb les dues lents del mòdul 5 — la lineal i global (PCA, 05-03) i la no lineal centrada en veïnatges (t-SNE, 05-05):
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_esc)
X_tsne = TSNE(n_components=2, perplexity=30,
random_state=42).fit_transform(X_esc)
fig, eixos = plt.subplots(1, 2, figsize=(13, 5))
for eix, dades, titol in [(eixos[0], X_pca, "PCA"), (eixos[1], X_tsne, "t-SNE")]:
sc = eix.scatter(dades[:, 0], dades[:, 1], c=clients["segment"],
cmap="tab10", s=8, alpha=0.6)
eix.set_title(titol)
plt.colorbar(sc, label="Segment"); plt.show()
print("Variancia explicada PCA:", pca.explained_variance_ratio_.round(2))Recorda les regles de lectura de 05-05: en PCA les distàncies globals signifiquen alguna cosa (i pca.components_ et diu quina combinació de features és cada eix); en t-SNE només la pertinença als grups és interpretable — ni mides ni distàncies entre illes. Si els colors de K-means apareixen com a regions coherents en totes dues projeccions, el clustering guanya una altra confirmació visual.
Perfilat: de centroides a noms de negoci
La fase que converteix l'anàlisi en producte — taula de mitjanes per segment en unitats originals, no escalades:
perfil = clients.groupby("segment").agg(
n=("segment", "size"),
recencia=("recencia_dies", "mean"),
comandes=("comandes_12m", "mean"),
tiquet=("tiquet_mitja_eur", "mean"),
pct_frescos=("pct_frescos", "mean"),
antiguitat=("antiguitat_dies", "mean"),
).round(1)
perfil["despesa_anual"] = (perfil["comandes"] * perfil["tiquet"]).round(0)
print(perfil.to_string())Amb aquestes xifres es bateja cada segment. Un resultat típic (els teus números variaran; els noms els poses mirant la teva taula, no aquesta):
| Segment | n | Recència | Comandes/any | Tiquet | Despesa anual | Nom de negoci |
|---|---|---|---|---|---|---|
| 0 | ≈ 160 | 8 dies | 88 | 84 € | ≈ 7.400 € | VIP |
| 1 | ≈ 640 | 13 dies | 44 | 46 € | ≈ 2.000 € | Habituals |
| 2 | ≈ 600 | 36 dies | 12 | 31 € | ≈ 370 € | Ocasionals |
| 3 | ≈ 400 | 165 dies | 4 | 37 € | ≈ 150 € | Adormits |
| 4 | ≈ 200 | 11 dies | 3 | 26 € | ≈ 80 € | Nous |
I el moment de la veritat del nostre experiment: creua clients["segment"] amb els arquetips sembrats (pd.crosstab(clients["segment"], arquetip)). Hi veuràs una correspondència forta però imperfecta — fronteres borroses entre habituals i ocasionals, nous repartits —, que és exactament el que passa amb segments reals: el clustering recupera l'estructura, no la partició exacta.
Accions per segment i com mesurar-les
Un segment sense acció és un gràfic bonic. La taula que màrqueting espera:
| Segment | Acció proposada | Mètrica d'èxit |
|---|---|---|
| VIP | Programa de fidelitat prèmium, enviament gratis | Retenció a 12 mesos |
| Habituals | Subscripció de cistell recurrent | Conversió a subscripció |
| Ocasionals | Campanyes en les seves categories més comprades | Freqüència de comanda |
| Adormits | Email de reactivació amb cupó | Taxa de reactivació a 30 dies |
| Nous | Onboarding: 3 primeres compres guiades | Supervivència a la 4a comanda |
I com sabrem si l'acció funciona? Amb el test A/B de 02-04 "Inferència estadística": dins de cada segment, un grup aleatori rep l'acció i un altre no, i es contrasta la diferència en la mètrica d'èxit amb el seu test d'hipòtesi. Sense grup de control, qualsevol millora és atribuïble a l'estacionalitat o a l'atzar — el clustering proposa, la inferència disposa.
Dels segments a producció
Tanquem amb l'ofici de 08-02 "Implementació de models en producció". El pipeline transformacions + escalat + K-means se serialitza i s'executa com a scoring batch: cada nit (o cada setmana — els segments es mouen a poc a poc), es recalculen les features de cada client i se li assigna segment amb predict, escrivint el resultat allà on el CRM el llegeixi:
import joblib
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
def log_rfm(X):
X = X.copy()
for col in ["recencia", "frequencia", "monetari"]:
X[col] = np.log1p(X[col])
return X
pipeline_seg = Pipeline([
("log", FunctionTransformer(log_rfm)),
("esc", StandardScaler()),
("km", KMeans(n_clusters=5, n_init=10, random_state=42)),
]).fit(X)
joblib.dump(pipeline_seg, "segmentador_mercafresh.joblib")
# En el job nocturn:
model = joblib.load("segmentador_mercafresh.joblib")
clients["segment"] = model.predict(X)Dues vigilàncies del monitoratge de 08-03 també apliquen aquí: la mida de cada segment al llarg del temps (si els adormits creixen un 30 %, és una alarma de negoci, no del model) i la deriva dels centroides quan es reentrena — si els perfils canvien de significat, els noms i les campanyes s'han de revisar amb ells. I el recordatori de 08-04: segmentar per tractar diferent els clients exigeix revisar que cap segment no sigui un proxy d'un col·lectiu protegit.
Errors Comuns i Consells
- Oblidar l'escalat (o el log). Sense estandarditzar,
monetaridicta els clústers tot sol; sense log, els quatre clients extrems es converteixen en "segments" de quatre persones. És l'error número u en segmentació. - Triar k només per la mètrica. Una silhouette de 0,41 amb k = 2 pot ser pitjor negoci que 0,35 amb k = 5: dos segments no donen joc comercial. Mètrica i accionabilitat decideixen juntes.
- Perfilar en unitats escalades. Un centroide de "−0,3 recències estàndard" no el pots explicar a màrqueting. El perfilat, sempre en unitats originals.
- Tractar els segments com a veritats eternes. Són una foto: els clients migren entre segments i aquesta migració (quants habituals cauen a adormits cada mes?) sovint és més valuosa que la foto mateixa.
- Llançar accions sense grup de control. Sense A/B no hi ha atribució; hauràs gastat el pressupost a confirmar els teus biaixos.
Reptes per ampliar
- Més features, millors segments. Afegeix al vector variables de comportament: percentatge de compres amb cupó, diversitat de categories, taxa de devolucions, canal (app/web). Pista: repeteix colze + silhouette des de zero — amb més dimensions el k òptim pot canviar — i vigila amb PCA quanta variància aporten de debò les columnes noves.
- Clustering de productes. Gira la matriu: en lloc de clients descrits per compres, productes descrits per qui els compra (o per coaparició en cistells). Pista: la matriu producte × client és enorme i dispersa — redueix primer amb el PCA de 05-03 (o
TruncatedSVD, la seva variant per a matrius disperses) i agrupa després; els grups resultants alimenten recomanacions del tipus "qui compra això...". - Panell de seguiment. Construeix amb matplotlib un informe mensual automàtic: mida de cada segment al llarg del temps, despesa mitjana per segment i matriu de migracions mes a mes. Pista: desa cada scoring batch amb la seva data; la migració és un
pd.crosstab(segment_mes_anterior, segment_actual)— i converteix-lo en el monitoratge permanent que demanava 08-03.
Recapitulació del mòdul 9
Cinc projectes, cinc problemes diferents, un mateix mètode. La taula que resumeix el que has practicat:
| Projecte | Tipus de problema | Dataset | Tècniques protagonistes | Lliçó central |
|---|---|---|---|---|
| 1. Habitatges | Regressió | California Housing | Pipeline, Ridge/Lasso, Random Forest, HistGradientBoosting, CV, residus | L'EDA anticipa quin model guanyarà |
| 2. Imatges | Classificació multiclasse | digits + Fashion-MNIST | SVM, PCA, MLP vs. CNN, dropout, early stopping | Comença simple; que les dades justifiquin cada capa |
| 3. Sentiments | Classificació de text | Ressenyes (fictici) | Neteja, TF-IDF, n-grames, MultinomialNB, interpretació de pesos | La representació importa tant com l'algorisme |
| 4. Frau | Classificació desequilibrada | Sintètic (make_classification) | class_weight, remostreig, corba PR, AUC-PR, llindar per costos | Separa el model (probabilitats) de la decisió (euros) |
| 5. Segmentació | No supervisat | MercaFresh sintètic | RFM, K-means, jeràrquic, DBSCAN, PCA/t-SNE, perfilat, A/B | Sense etiquetes, l'èxit és estabilitat + accionabilitat |
I transversal als cinc: definir el problema i la mètrica abans de tocar dades, apartar el test al principi, encapsular en Pipeline, comparar contra un baseline amb validació creuada honesta, analitzar els errors en lloc de només comptar-los, i traduir el resultat a l'idioma de negoci.
Conclusió
El cercle està tancat: MercaFresh va obrir el curs ensenyant-te cada peça per separat i el tanca veient-te ensamblar-les totes sense ajuda — n'has descobert els segments de clients des de zero, els has validat amb tres algorismes i dues projeccions, els has posat nom, acció i grup de control, i els has deixat servint-se en batch amb el seu monitoratge previst. Ja no ets la persona que va començar el mòdul 1: tens un mètode complet i cinc projectes que ho demostren, a punt per convertir-se en l'embrió del teu portafolis. El que queda no és aprendre més lliçons, sinó continuar aprenent pel teu compte: al mòdul 10 et deixem el mapa — llibres, cursos, comunitats i eines — perquè el final d'aquest curs sigui només el principi del teu camí en el machine learning.
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
