Guida definitiva al clustering gerarchico con Python e Scikit-Learn PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Guida definitiva al clustering gerarchico con Python e Scikit-Learn

Introduzione

In questa guida, ci concentreremo sull'implementazione del Algoritmo di clustering gerarchico con Scikit-Learn per risolvere un problema di marketing.

Dopo aver letto la guida, capirai:

  • Quando applicare il clustering gerarchico
  • Come visualizzare il set di dati per capire se è adatto per il clustering
  • Come pre-elaborare le funzionalità e progettare nuove funzionalità in base al set di dati
  • Come ridurre la dimensionalità del set di dati utilizzando PCA
  • Come usare e leggere un dendrogramma per separare i gruppi
  • Quali sono i diversi metodi di collegamento e le metriche di distanza applicate ai dendrogrammi e agli algoritmi di clustering
  • Quali sono le strategie di clustering agglomerato e divisivo e come funzionano
  • Come implementare il clustering gerarchico agglomerato con Scikit-Learn
  • Quali sono i problemi più frequenti quando si ha a che fare con algoritmi di clustering e come risolverli

Nota: Puoi scaricare il taccuino contenente tutto il codice in questa guida qui.

Motivazione

Immagina uno scenario in cui fai parte di un team di data science che si interfaccia con il reparto marketing. Il marketing raccoglie da tempo i dati sugli acquisti dei clienti e vogliono capire, in base ai dati raccolti, se ce ne sono somiglianze tra i clienti. Tali somiglianze dividono i clienti in gruppi e avere gruppi di clienti aiuta nel targeting di campagne, promozioni, conversioni e nella costruzione di migliori relazioni con i clienti.

C'è un modo in cui potresti aiutare a determinare quali clienti sono simili? Quanti di loro appartengono allo stesso gruppo? E quanti gruppi diversi ci sono?

Un modo per rispondere a queste domande è usare a il clustering algoritmi, come K-Means, DBSCAN, Hierarchical Clustering, ecc. In termini generali, gli algoritmi di clustering trovano somiglianze tra i punti dati e li raggruppano.

In questo caso, i nostri dati di marketing sono piuttosto piccoli. Abbiamo informazioni su solo 200 clienti. Considerando il team di marketing, è importante che possiamo spiegare loro chiaramente come sono state prese le decisioni in base al numero di cluster, spiegando loro quindi come funziona effettivamente l'algoritmo.

Poiché i nostri dati sono piccoli e la spiegazione è un fattore importante, possiamo sfruttare Clustering gerarchico risolvere questo problema. Questo processo è anche noto come Analisi del clustering gerarchico (HCA).

Uno dei vantaggi dell'HCA è che è interpretabile e funziona bene su piccoli set di dati.

Un'altra cosa da prendere in considerazione in questo scenario è che HCA è un senza sorveglianza algoritmo. Quando si raggruppano i dati, non avremo modo di verificare che stiamo identificando correttamente che un utente appartiene a un gruppo specifico (non conosciamo i gruppi). Non ci sono etichette con cui confrontare i nostri risultati. Se abbiamo identificato correttamente i gruppi, ciò verrà successivamente confermato dal reparto marketing su base giornaliera (misurata da metriche come ROI, tassi di conversione, ecc.).

Ora che abbiamo capito il problema che stiamo cercando di risolvere e come risolverlo, possiamo iniziare a dare un'occhiata ai nostri dati!

Breve analisi esplorativa dei dati

Nota: È possibile scaricare il set di dati utilizzato in questa guida qui.

Dopo aver scaricato il set di dati, notare che si tratta di un CSV (valori separati da virgola) file chiamato shopping-data.csv. Per semplificare l'esplorazione e la manipolazione dei dati, li caricheremo in a DataFrame usando Panda:

import pandas as pd


path_to_file = 'home/projects/datasets/shopping-data.csv'
customer_data = pd.read_csv(path_to_file)

Il marketing ha affermato di aver raccolto 200 record di clienti. Possiamo verificare se i dati scaricati sono completi di 200 righe utilizzando il file shape attributo. Ci dirà quante righe e colonne abbiamo, rispettivamente:

customer_data.shape

Questo risulta in:

(200, 5)

Grande! I nostri dati sono completi di 200 righe (record dei clienti) e abbiamo anche 5 colonne (caratteristiche). Per vedere quali caratteristiche il reparto marketing ha raccolto dai clienti, possiamo vedere i nomi delle colonne con il columns attributo. Per farlo, esegui:

customer_data.columns

Lo script sopra restituisce:

Index(['CustomerID', 'Genre', 'Age', 'Annual Income (k$)',
       'Spending Score (1-100)'],
      dtype='object')

Qui, vediamo che il marketing ha generato a CustomerID, raccolto il Genre, Age, Annual Income (in migliaia di dollari) e a Spending Score passando da 1 a 100 per ciascuno dei 200 clienti. Alla richiesta di chiarimenti, hanno affermato che i valori nel Spending Score la colonna indica la frequenza con cui una persona spende denaro in un centro commerciale su una scala da 1 a 100. In altre parole, se un cliente ha un punteggio di 0, questa persona non spende mai denaro e se il punteggio è 100, abbiamo appena individuato il la spesa più alta.

Diamo una rapida occhiata alla distribuzione di questo punteggio per esaminare le abitudini di spesa degli utenti nel nostro set di dati. Ecco dove i Panda hist() il metodo viene in aiuto:

customer_data['Spending Score (1-100)'].hist()

img

Osservando l'istogramma vediamo che più di 35 clienti hanno punteggi intermedi 40 ed 60, quindi meno di 25 hanno punteggi intermedi 70 ed 80. Quindi la maggior parte dei nostri clienti lo sono spesa equilibrata, seguito da spenditori da moderati a elevati. Possiamo anche vedere che c'è una riga dopo 0, a sinistra della distribuzione e un'altra riga prima di 100, a destra della distribuzione. Questi spazi vuoti probabilmente significano che la distribuzione non contiene persone che non spendono, che avrebbero un punteggio di 0, e che non ci sono anche persone che spendono molto con un punteggio di 100.

Per verificare se ciò è vero, possiamo guardare i valori minimo e massimo della distribuzione. Questi valori possono essere facilmente trovati come parte delle statistiche descrittive, quindi possiamo usare il describe() metodo per comprendere altre distribuzioni di valori numerici:


customer_data.describe().transpose()

Questo ci darà una tabella da cui possiamo leggere le distribuzioni di altri valori del nostro set di dati:

 						count 	mean 	std 		min 	25% 	50% 	75% 	max
CustomerID 				200.0 	100.50 	57.879185 	1.0 	50.75 	100.5 	150.25 	200.0
Age 					200.0 	38.85 	13.969007 	18.0 	28.75 	36.0 	49.00 	70.0
Annual Income (k$) 		200.0 	60.56 	26.264721 	15.0 	41.50 	61.5 	78.00 	137.0
Spending Score (1-100) 	200.0 	50.20 	25.823522 	1.0 	34.75 	50.0 	73.00 	99.0

La nostra ipotesi è confermata. Il min valore del Spending Score is 1 e il massimo è 99. Quindi non abbiamo 0 or 100 punteggio spender. Diamo quindi un'occhiata alle altre colonne del trasposto describe tavolo. Quando si guarda il mean ed std colonne, possiamo vederlo per Age , il mean is 38.85 e la std è di circa 13.97. Lo stesso accade per Annual Income, Con mean of 60.56 ed std 26.26, E per Spending Score con una mean of 50 ed std of 25.82. Per tutte le funzionalità, il mean è lontano dalla deviazione standard, che indica i nostri dati hanno un'elevata variabilità.

Per capire meglio come variano i nostri dati, tracciamo il Annual Income distribuzione:

customer_data['Annual Income (k$)'].hist()

Che ci darà:

img

Nota nell'istogramma che la maggior parte dei nostri dati, più di 35 clienti, è concentrata vicino al numero 60, sulla nostra mean, sull'asse orizzontale. Ma cosa succede mentre ci muoviamo verso le estremità della distribuzione? Andando verso sinistra, dalla media di $ 60.560, il valore successivo che incontreremo è $ 34.300: la media ($ 60.560) meno la variazione standard ($ 26.260). Se ci allontaniamo ulteriormente a sinistra della distribuzione dei dati, si applica una regola simile: sottraiamo la variazione standard ($26.260) dal valore corrente ($34.300). Pertanto, incontreremo un valore di $ 8.040. Nota come i nostri dati sono passati rapidamente da $ 60 a $ 8. Sta “saltando” $ 26.260 ogni volta – variando molto, ed è per questo che abbiamo una variabilità così elevata.

img

La variabilità e la dimensione dei dati sono importanti nell'analisi del clustering perché le misurazioni della distanza della maggior parte degli algoritmi di clustering sono sensibili alle grandezze dei dati. La differenza di dimensioni può modificare i risultati del clustering facendo sembrare un punto più vicino o più distante da un altro di quanto non sia in realtà, distorcendo il raggruppamento effettivo dei dati.

Finora abbiamo visto la forma dei nostri dati, alcune delle sue distribuzioni e le statistiche descrittive. Con Pandas, possiamo anche elencare i nostri tipi di dati e vedere se tutte le nostre 200 righe sono piene o ne hanno alcune null valori:

customer_data.info()

Questo risulta in:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns):
 #   Column                  Non-Null Count  Dtype 
---  ------                  --------------  ----- 
 0   CustomerID              200 non-null    int64 
 1   Genre                   200 non-null    object
 2   Age                     200 non-null    int64 
 3   Annual Income (k$)      200 non-null    int64 
 4   Spending Score (1-100)  200 non-null    int64 
dtypes: int64(4), object(1)
memory usage: 7.9+ KB

Qui possiamo vedere che non ci sono null valori nei dati e che abbiamo solo una colonna categoriale – Genre. In questa fase, è importante tenere a mente quali funzionalità sembrano interessanti da aggiungere al modello di clustering. Se vogliamo aggiungere la colonna Genere al nostro modello, dovremo trasformarne i valori da categorico a numerico.

Vediamo come Genre si riempie dando una rapida occhiata ai primi 5 valori dei nostri dati:

customer_data.head() 

Questo risulta in:

    CustomerID 	Genre 	Age 	Annual Income (k$) 	Spending Score (1-100)
0 	1 			Male 	19 		15 					39
1 	2 			Male 	21 		15 					81
2 	3 			Female 	20 		16 					6
3 	4 			Female 	23 		16 					77
4 	5 			Female 	31 		17 					40

Sembra che abbia solo Female ed Male categorie. Possiamo esserne certi dando un'occhiata ai suoi valori unici con unique:

customer_data['Genre'].unique()

Ciò conferma la nostra ipotesi:

array(['Male', 'Female'], dtype=object)

Finora sappiamo che abbiamo solo due generi, se prevediamo di utilizzare questa funzione sul nostro modello, Male potrebbe essere trasformato in 0 ed Female a 1. È anche importante controllare la proporzione tra i generi, per vedere se sono equilibrati. Possiamo farlo con il value_counts() metodo e il suo argomento normalize=True per mostrare la percentuale tra Male ed Female:

customer_data['Genre'].value_counts(normalize=True)

Questo produce:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

Abbiamo il 56% delle donne nel set di dati e il 44% degli uomini. La differenza tra loro è solo del 16% e i nostri dati non sono 50/50 ma lo sono abbastanza equilibrato per non creare problemi. Se i risultati fossero 70/30, 60/40, allora potrebbe essere stato necessario raccogliere più dati o utilizzare una sorta di tecnica di aumento dei dati per rendere quel rapporto più equilibrato.

Fino ad ora, tutte le funzionalità ma Age, sono stati brevemente esplorati. In quali preoccupazioni Age, di solito è interessante suddividerlo in bin per poter segmentare i clienti in base alle loro fasce d'età. Se lo facciamo, dovremmo trasformare le categorie di età in un numero prima di aggiungerle al nostro modello. In questo modo, invece di utilizzare la categoria 15-20 anni, conteremmo quanti clienti ci sono nella 15-20 categoria, e quello sarebbe un numero in una nuova colonna chiamata 15-20.

Consigli: In questa guida presentiamo solo una breve analisi esplorativa dei dati. Ma puoi andare oltre e dovresti andare oltre. Puoi vedere se ci sono differenze di reddito e differenze di punteggio in base al genere e all'età. Questo non solo arricchisce l'analisi, ma porta a migliori risultati del modello. Per approfondire l'analisi esplorativa dei dati, consulta il capitolo EDA nel “Previsione pratica dei prezzi delle abitazioni - Machine Learning in Python" Progetto guidato.

Dopo aver congetturato su cosa si potrebbe fare con entrambi i categoriali - o categoriali essere - Genre ed Age colonne, applichiamo quanto discusso.

Codifica delle variabili e ingegneria delle caratteristiche

Iniziamo dividendo il Age in gruppi che variano in 10, in modo da avere 20-30, 30-40, 40-50 e così via. Poiché il nostro cliente più giovane ha 15 anni, possiamo iniziare a 15 anni e finire a 70, che è l'età del cliente più anziano nei dati. A partire da 15 e terminando a 70, avremmo intervalli 15-20, 20-30, 30-40, 40-50, 50-60 e 60-70.

Raggruppare o bidone Age valori in questi intervalli, possiamo usare i Panda cut() metodo per tagliarli in contenitori e quindi assegnarli a uno nuovo Age Groups colonna:

intervals = [15, 20, 30, 40, 50, 60, 70]
col = customer_data['Age']
customer_data['Age Groups'] = pd.cut(x=col, bins=intervals)


customer_data['Age Groups'] 

Questo risulta in:

0      (15, 20]
1      (20, 30]
2      (15, 20]
3      (20, 30]
4      (30, 40]
         ...   
195    (30, 40]
196    (40, 50]
197    (30, 40]
198    (30, 40]
199    (20, 30]
Name: Age Groups, Length: 200, dtype: category
Categories (6, interval[int64, right]): [(15, 20] < (20, 30] < (30, 40] < (40, 50] < (50, 60] < (60, 70]]

Si noti che quando si osservano i valori delle colonne, c'è anche una riga che specifica che abbiamo 6 categorie e mostra tutti gli intervalli di dati raggruppati. In questo modo, abbiamo classificato i nostri dati numerici precedenti e ne abbiamo creato uno nuovo Age Groups caratteristica.

E quanti clienti abbiamo in ogni categoria? Possiamo saperlo rapidamente raggruppando la colonna e contando i valori con groupby() ed count():

customer_data.groupby('Age Groups')['Age Groups'].count()

Questo risulta in:

Age Groups
(15, 20]    17
(20, 30]    45
(30, 40]    60
(40, 50]    38
(50, 60]    23
(60, 70]    17
Name: Age Groups, dtype: int64

È facile notare che la maggior parte dei clienti ha un'età compresa tra 30 e 40 anni, seguita da clienti tra i 20 e i 30 e poi i clienti tra i 40 ei 50. Questa è anche una buona informazione per il reparto Marketing.

Al momento, abbiamo due variabili categoriali, Age ed Genre, che dobbiamo trasformare in numeri per poterli utilizzare nel nostro modello. Ci sono molti modi diversi per realizzare questa trasformazione: useremo i Panda get_dummies() metodo che crea una nuova colonna per ogni intervallo e genere e quindi riempie i suoi valori con 0 e 1- questo tipo di operazione viene chiamata codifica one-hot. Vediamo come appare:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Questo ci darà un'anteprima della tabella risultante:

img

Con l'output, è facile vedere che la colonna Genre era diviso in colonne – Genre_Female ed Genre_Male. Quando il cliente è una donna, Genre_Female è uguale a 1, e quando il cliente è maschio, è uguale 0.

Anche il Age Groups colonna è stata suddivisa in 6 colonne, una per ogni intervallo, ad esempio Age Groups_(15, 20], Age Groups_(20, 30], e così via. Allo stesso modo di Genre, quando il cliente ha 18 anni, il Age Groups_(15, 20] valore è 1 e il valore di tutte le altre colonne è 0.

I vantaggio della codifica one-hot è la semplicità nel rappresentare i valori delle colonne, è semplice capire cosa sta succedendo, mentre il svantaggio è che ora abbiamo creato 8 colonne aggiuntive, per riassumere con le colonne che già avevamo.

avvertimento: se si dispone di un set di dati in cui il numero di colonne codificate one-hot supera il numero di righe, è meglio utilizzare un altro metodo di codifica per evitare problemi di dimensionalità dei dati.

La codifica one-hot aggiunge anche 0 ai nostri dati, rendendoli più scarsi, il che può essere un problema per alcuni algoritmi sensibili alla scarsità dei dati.

Per le nostre esigenze di clustering, la codifica one-hot sembra funzionare. Ma possiamo tracciare i dati per vedere se ci sono davvero gruppi distinti da raggruppare.

Tracciatura di base e riduzione della dimensionalità

Il nostro set di dati ha 11 colonne e ci sono alcuni modi in cui possiamo visualizzare quei dati. Il primo è tracciarlo in 10 dimensioni (buona fortuna). Dieci perché il Customer_ID la colonna non viene presa in considerazione. Il secondo è tracciare le nostre caratteristiche numeriche iniziali e il terzo è trasformare le nostre 10 caratteristiche in 2, quindi, eseguendo una riduzione della dimensionalità.

Tracciare ogni coppia di dati

Poiché tracciare 10 dimensioni è un po' impossibile, opteremo per il secondo approccio: tracciamo le nostre caratteristiche iniziali. Possiamo sceglierne due per la nostra analisi di clustering. Un modo in cui possiamo vedere tutte le nostre coppie di dati combinate è con un Seaborn pairplot():

import seaborn as sns


customer_data = customer_data.drop('CustomerID', axis=1)

sns.pairplot(customer_data)

Che visualizza:

img

A colpo d'occhio, possiamo individuare i grafici a dispersione che sembrano avere gruppi di dati. Uno che sembra interessante è il grafico a dispersione che combina Annual Income ed Spending Score. Si noti che non esiste una chiara separazione tra gli altri grafici a dispersione variabili. Al massimo, possiamo forse dire che ci sono due distinte concentrazioni di punti nel Spending Score vs Age grafico a dispersione.

Entrambi i grafici a dispersione sono costituiti da Annual Income ed Spending Score sono essenzialmente gli stessi. Possiamo vederlo due volte perché gli assi x e y sono stati scambiati. Dando un'occhiata a uno di essi, possiamo vedere quelli che sembrano essere cinque gruppi diversi. Tracciamo solo queste due caratteristiche con un Seaborn scatterplot() per dare un'occhiata più da vicino:

sns.scatterplot(x=customer_data['Annual Income (k$)'],
                y=customer_data['Spending Score (1-100)'])

img

Osservando più da vicino, possiamo sicuramente distinguere 5 diversi gruppi di dati. Sembra che i nostri clienti possano essere raggruppati in base a quanto guadagnano in un anno e quanto spendono. Questo è un altro punto rilevante della nostra analisi. È importante prendere in considerazione solo due caratteristiche per raggruppare i nostri clienti. Qualsiasi altra informazione che abbiamo su di loro non sta entrando nell'equazione. Questo dà significato all'analisi: se sappiamo quanto guadagna e spende un cliente, possiamo facilmente trovare le somiglianze di cui abbiamo bisogno.

img

È fantastico! Finora abbiamo già due variabili per costruire il nostro modello. Oltre a ciò che rappresenta, rende anche il modello più semplice, parsimonioso e più spiegabile.

Dai un'occhiata alla nostra guida pratica e pratica per l'apprendimento di Git, con le migliori pratiche, gli standard accettati dal settore e il cheat sheet incluso. Smetti di cercare su Google i comandi Git e in realtà imparare esso!

Nota: La scienza dei dati di solito predilige gli approcci il più semplici possibile. Non solo perché è più facile da spiegare per l'azienda, ma anche perché è più diretto: con 2 funzionalità e un modello spiegabile, è chiaro cosa sta facendo il modello e come sta funzionando.

Tracciare i dati dopo aver utilizzato PCA

Sembra che il nostro secondo approccio sia probabilmente il migliore, ma diamo anche un'occhiata al nostro terzo approccio. Può essere utile quando non possiamo tracciare i dati perché hanno troppe dimensioni o quando non ci sono concentrazioni di dati o una chiara separazione in gruppi. Quando si verificano queste situazioni, è consigliabile provare a ridurre le dimensioni dei dati con un metodo chiamato Analisi dei componenti principali (PCA).

Nota: La maggior parte delle persone usa la PCA per la riduzione della dimensionalità prima della visualizzazione. Esistono altri metodi che aiutano nella visualizzazione dei dati prima del clustering, ad esempio Clustering spaziale basato sulla densità di applicazioni con rumore (DBSCAN) ed Mappe auto-organizzate (SOM) raggruppamento. Entrambi sono algoritmi di clustering, ma possono essere utilizzati anche per la visualizzazione dei dati. Poiché l'analisi di clustering non ha standard aurei, è importante confrontare diverse visualizzazioni e diversi algoritmi.

PCA ridurrà le dimensioni dei nostri dati cercando di preservare il maggior numero possibile di informazioni. Diamo prima un'idea di come funziona PCA, quindi possiamo scegliere a quante dimensioni di dati ridurre i nostri dati.

Per ogni coppia di funzionalità, PCA verifica se i valori maggiori di una variabile corrispondono ai valori maggiori dell'altra variabile e fa lo stesso per i valori minori. Quindi, essenzialmente calcola quanto i valori delle caratteristiche variano l'uno rispetto all'altro: lo chiamiamo loro covarianza. Tali risultati vengono quindi organizzati in una matrice, ottenendo a matrice di covarianza.

Dopo aver ottenuto la matrice di covarianza, la PCA cerca di trovare una combinazione lineare di caratteristiche che la spieghi meglio: si adatta ai modelli lineari finché non identifica quello che spiega la matrice di covarianza. massimo quantità di varianza.

Note:: PCA è una trasformazione lineare e la linearità è sensibile alla scala dei dati. Pertanto, PCA funziona meglio quando tutti i valori dei dati sono sulla stessa scala. Questo può essere fatto sottraendo la colonna significare dai suoi valori e dividendo il risultato per la sua deviazione standard. Quello si chiama standardizzazione dei dati. Prima di utilizzare PCA, assicurati che i dati siano ridimensionati! Se non sai come fare, leggi il nostro "Ridimensionamento delle funzionalità dei dati con Scikit-Learn per l'apprendimento automatico in Python"!

Con la migliore linea (combinazione lineare) trovata, PCA ottiene le direzioni dei suoi assi, chiamati autovettori, e i suoi coefficienti lineari, il autovalori. La combinazione degli autovettori e degli autovalori – o direzioni e coefficienti degli assi – sono i Componenti principali dell'APC. Ed è allora che possiamo scegliere il nostro numero di dimensioni in base alla varianza spiegata di ciascuna caratteristica, comprendendo quali componenti principali vogliamo mantenere o scartare in base a quanta varianza spiegano.

Dopo aver ottenuto i componenti principali, PCA utilizza gli autovettori per formare un vettore di caratteristiche che riorientano i dati dagli assi originali a quelli rappresentati dai componenti principali: è così che le dimensioni dei dati vengono ridotte.

Nota: Un dettaglio importante da prendere in considerazione qui è che, a causa della sua natura lineare, PCA concentrerà la maggior parte della varianza spiegata nelle prime componenti principali. Quindi, quando si osserva la varianza spiegata, di solito i nostri primi due componenti saranno sufficienti. Ma ciò potrebbe essere fuorviante in alcuni casi, quindi cerca di continuare a confrontare grafici e algoritmi diversi durante il raggruppamento per vedere se contengono risultati simili.

Prima di applicare PCA, dobbiamo scegliere tra il Age colonna o il Age Groups colonne nei nostri dati codificati in precedenza one-hot. Poiché entrambe le colonne rappresentano le stesse informazioni, introdurle due volte influisce sulla varianza dei dati. Se la Age Groups viene scelta la colonna, è sufficiente rimuovere il file Age colonna utilizzando i Panda drop() metodo e riassegnarlo al customer_data_oh variabili:

customer_data_oh = customer_data_oh.drop(['Age'], axis=1)
customer_data_oh.shape 

Ora i nostri dati hanno 10 colonne, il che significa che possiamo ottenere un componente principale per colonna e scegliere quanti di essi utilizzeremo misurando quanto l'introduzione di una nuova dimensione spiega maggiormente la nostra varianza dei dati.

Facciamolo con Scikit-Learn PCA. Calcoleremo la varianza spiegata di ciascuna dimensione, data da explained_variance_ratio_ , quindi guarda la loro somma cumulativa con cumsum() :

from sklearn.decomposition import PCA

pca = PCA(n_components=10)
pca.fit_transform(customer_data_oh)
pca.explained_variance_ratio_.cumsum()

Le nostre varianze spiegate cumulative sono:

array([0.509337  , 0.99909504, 0.99946364, 0.99965506, 0.99977937,
       0.99986848, 0.99993716, 1.        , 1.        , 1.        ])

Possiamo vedere che la prima dimensione spiega il 50% dei dati e, quando combinata con la seconda dimensione, spiega il 99% percento. Ciò significa che le prime 2 dimensioni spiegano già il 99% dei nostri dati. Quindi possiamo applicare un PCA con 2 componenti, ottenere i nostri componenti principali e tracciarli:

from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pcs = pca.fit_transform(customer_data_oh)

pc1_values = pcs[:,0]
pc2_values = pcs[:,1]
sns.scatterplot(x=pc1_values, y=pc2_values)

img

Il grafico dei dati dopo PCA è molto simile al grafico che utilizza solo due colonne di dati senza PCA. Si noti che i punti che formano i gruppi sono più vicini e un po' più concentrati dopo l'APC rispetto a prima.

img

Visualizzazione della struttura gerarchica con i dendrogrammi

Finora, abbiamo esplorato i dati, colonne categoriali codificate a caldo, deciso quali colonne erano adatte per il clustering e ridotto la dimensionalità dei dati. I grafici indicano che abbiamo 5 cluster nei nostri dati, ma c'è anche un altro modo per visualizzare le relazioni tra i nostri punti e aiutare a determinare il numero di cluster, creando un dendrogramma (comunemente scritto erroneamente come dendogramma). dendro si intende albero in latino.

I dendrogramma è il risultato del collegamento di punti in un set di dati. È una rappresentazione visiva del processo di raggruppamento gerarchico. E come funziona il processo di clustering gerarchico? Beh... dipende, probabilmente una risposta che hai già sentito molto in Data Science.

Comprensione del clustering gerarchico

Quando il Algoritmo di clustering gerarchico (HCA) inizia a collegare i punti e trovare i cluster, può prima dividere i punti in 2 grandi gruppi, quindi dividere ciascuno di questi due gruppi in 2 gruppi più piccoli, con 4 gruppi in totale, che è il divisive ed top-down approccio.

In alternativa, può fare il contrario: può guardare tutti i punti dati, trovare 2 punti più vicini tra loro, collegarli e quindi trovare altri punti che sono i più vicini a quei punti collegati e continuare a costruire i 2 gruppi dal dal basso verso l'alto. Qual è agglomerativo approccio che svilupperemo.

Passaggi per eseguire il clustering gerarchico agglomerato

Per rendere ancora più chiaro l'approccio agglomerato, ci sono passaggi del Clustering gerarchico agglomerato (AHC) algoritmo:

  1. All'inizio, tratta ogni punto dati come un cluster. Pertanto, il numero di cluster all'inizio sarà K – mentre K è un numero intero che rappresenta il numero di punti dati.
  2. Forma un cluster unendo i due punti dati più vicini risultanti in cluster K-1.
  3. Forma più cluster unendo i due cluster più vicini risultanti in cluster K-2.
  4. Ripeti i tre passaggi precedenti fino a formare un grande grappolo.

Note:: Per semplificazione, stiamo dicendo "due punti dati più vicini" nei passaggi 2 e 3. Ma ci sono più modi per collegare i punti, come vedremo tra un po'.

Se invertiamo i passaggi dell'algoritmo ACH, passando da 4 a 1, questi sarebbero i passaggi da *Clustering gerarchico divisivo (DHC)*.

Si noti che gli HCA possono essere divisivi e dall'alto verso il basso, oppure agglomerati e dal basso verso l'alto. L'approccio DHC top-down funziona al meglio quando hai meno cluster, ma più grandi, quindi è più costoso dal punto di vista computazionale. D'altra parte, l'approccio AHC bottom-up è adatto quando si hanno molti cluster più piccoli. È computazionalmente più semplice, più utilizzato e più disponibile.

Nota: Sia dall'alto verso il basso che dal basso verso l'alto, la rappresentazione del dendrogramma del processo di raggruppamento inizierà sempre con una divisione in due e finirà con ogni singolo punto discriminato, una volta che la sua struttura sottostante è di un albero binario.

Tracciamo il nostro dendrogramma dei dati dei clienti per visualizzare le relazioni gerarchiche dei dati. Questa volta useremo il scipy libreria per creare il dendrogramma per il nostro set di dati:

import scipy.cluster.hierarchy as shc
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 7))
plt.title("Customers Dendrogram")


selected_data = customer_data_oh.iloc[:, 1:3]
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(Z=clusters)
plt.show()

L'output dello script è simile a questo:

img

Nello script sopra, abbiamo generato i cluster e i sottocluster con i nostri punti, definito come i nostri punti si collegherebbero (applicando il ward metodo) e come misurare la distanza tra i punti (utilizzando il euclidean metrico).

Con la trama del dendrogramma, è possibile visualizzare i processi descritti di DHC e AHC. Per visualizzare l'approccio dall'alto in basso, inizia dalla parte superiore del dendrogramma e scendi, e fai il contrario, iniziando dal basso e spostandoti verso l'alto per visualizzare l'approccio dal basso verso l'alto.

Metodi di collegamento

Esistono molti altri metodi di collegamento, comprendendo di più su come funzionano, sarai in grado di scegliere quello appropriato per le tue esigenze. Oltre a ciò, ognuno di essi produrrà risultati diversi quando applicato. Non esiste una regola fissa nell'analisi del cluster, se possibile, studiare la natura del problema per vedere quale si adatta meglio, testare metodi diversi e controllare i risultati.

Alcuni dei metodi di collegamento sono:

  • Collegamento unico: indicato anche come Vicino più vicino (NN). La distanza tra i cluster è definita dalla distanza tra i membri più vicini.

img

  • Collegamento completo: indicato anche come Vicino più lontano (FN), Algoritmo del punto più lontano, o Algoritmo Voor Hees. La distanza tra i cluster è definita dalla distanza tra i loro membri più lontani. Questo metodo è computazionalmente costoso.

img

  • Collegamento medio: conosciuto anche come UPGMA (Metodo dei gruppi di coppie non pesati con media aritmetica). La percentuale del numero di punti di ciascun cluster è calcolata rispetto al numero di punti dei due cluster se accorpati.

img

  • Collegamento ponderato: conosciuto anche come WPGMA (Metodo dei gruppi di coppie ponderate con media aritmetica). I singoli punti dei due cluster contribuiscono alla distanza aggregata tra un cluster più piccolo e uno più grande.
  • Collegamento centroide: indicato anche come UPGMC (Metodo del gruppo di coppie non ponderate utilizzando i centroidi). Un punto definito dalla media di tutti i punti (centroide) viene calcolato per ciascun cluster e la distanza tra i cluster è la distanza tra i rispettivi centroidi.

img

  • Collegamento di reparto: Conosciuto anche come MISSQ (Incremento minimo della somma dei quadrati). Specifica la distanza tra due cluster, calcola la somma dell'errore dei quadrati (ESS) e successivamente sceglie i cluster successivi in ​​base all'ESS più piccolo. Il metodo di Ward cerca di ridurre al minimo l'aumento di ESS ad ogni passaggio. Pertanto, riducendo al minimo l'errore.

img

Metriche di distanza

Oltre al collegamento, possiamo anche specificare alcune delle metriche di distanza più utilizzate:

  • euclideo: indicato anche come Pitagorico o rettilineo distanza. Calcola la distanza tra due punti nello spazio, misurando la lunghezza di un segmento di linea che passa tra di loro. Usa il teorema di Pitagora e il valore della distanza è il risultato (C) dell'equazione:

$$
c^2 = a^2 + b^2
$$

  • Manhattan: chiamato anche Blocco urbano, taxi distanza. È la somma delle differenze assolute tra le misure in tutte le dimensioni di due punti. Se quelle dimensioni sono due, è analogo a fare una destra e poi una sinistra quando si cammina per un isolato.

img

  • Minkowski: è una generalizzazione delle distanze euclidee e di Manhattan. È un modo per calcolare le distanze in base alle differenze assolute rispetto all'ordine della metrica di Minkowski p. Sebbene sia definito per qualsiasi p> 0, è usato raramente per valori diversi da 1, 2 e ∞ (infinito). La distanza di Minkowski è la stessa della distanza di Manhattan quando p = 1, e lo stesso della distanza euclidea quando p = 2.

$$
Dsinistra(X,Ydestra) = sinistra(somma_{i=1}^n |x_i-y_i|^destra)^{frac{1}{p}}
$$

img

  • Chebyshev: conosciuto anche come Scacchiera distanza. È il caso estremo della distanza di Minkowski. Quando usiamo l'infinito come valore del parametro p (p = ∞), si ottiene una metrica che definisce la distanza come la massima differenza assoluta tra le coordinate.
  • coseno: è la distanza angolare del coseno tra due sequenze di punti, o vettori. La somiglianza del coseno è il prodotto scalare dei vettori diviso per il prodotto delle loro lunghezze.
  • Jaccard: misura la somiglianza tra insiemi finiti di punti. È definito come il numero totale di punti (cardinalità) nei punti comuni di ciascun insieme (intersezione), diviso per il numero totale di punti (cardinalità) dei punti totali di entrambi gli insiemi (unione).
  • Jensen Shannon: basato sulla divergenza Kullback-Leibler. Considera le distribuzioni di probabilità dei punti e misura la somiglianza tra tali distribuzioni. È un metodo popolare di teoria della probabilità e statistica.

Abbiamo scelto reparto ed euclideo per il dendrogramma perché sono il metodo e la metrica più comunemente usati. Di solito danno buoni risultati poiché Ward collega i punti in base alla riduzione al minimo degli errori e Euclidea funziona bene in dimensioni inferiori.

In questo esempio, stiamo lavorando con due caratteristiche (colonne) dei dati di marketing e 200 osservazioni o righe. Poiché il numero di osservazioni è maggiore del numero di caratteristiche (200 > 2), stiamo lavorando in uno spazio a bassa dimensione.

Quando il numero di funzioni (F) è maggiore del numero di osservazioni (N) – per lo più scritto come f >> N, significa che abbiamo un file spazio ad alta dimensione.

Se dovessimo includere più attributi, quindi abbiamo più di 200 caratteristiche, la distanza euclidea potrebbe non funzionare molto bene, poiché avrebbe difficoltà a misurare tutte le piccole distanze in uno spazio molto grande che diventa solo più grande. In altre parole, l'approccio della distanza euclidea ha difficoltà a lavorare con i dati scarsità. Questo è un problema che viene chiamato la maledizione della dimensionalità. I valori di distanza diventerebbero così piccoli, come se si "diluissero" nello spazio più ampio, distorti fino a diventare 0.

Nota: Se mai incontri un set di dati con f >> pag, probabilmente utilizzerai altre metriche di distanza, come il Mahalanobis distanza. In alternativa, puoi anche ridurre le dimensioni del set di dati, utilizzando Analisi dei componenti principali (PCA). Questo problema è frequente soprattutto quando si raggruppano i dati di sequenziamento biologico.

Abbiamo già discusso di metriche, collegamenti e di come ognuno di essi può influire sui nostri risultati. Continuiamo ora l'analisi del dendrogramma e vediamo come può darci un'indicazione del numero di cluster nel nostro set di dati.

Trovare un numero interessante di cluster in un dendrogramma equivale a trovare lo spazio orizzontale più grande che non ha linee verticali (lo spazio con le linee verticali più lunghe). Ciò significa che c'è più separazione tra i cluster.

Possiamo tracciare una linea orizzontale che passa per quella distanza più lunga:

plt.figure(figsize=(10, 7))
plt.title("Customers Dendogram with line")
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(clusters)
plt.axhline(y = 125, color = 'r', linestyle = '-')

img

Dopo aver individuato la linea orizzontale, contiamo quante volte le nostre linee verticali sono state attraversate da essa – in questo esempio, 5 volte. Quindi 5 sembra una buona indicazione del numero di cluster che hanno la maggiore distanza tra loro.

Note:: Il dendrogramma deve essere considerato solo come riferimento quando utilizzato per scegliere il numero di cluster. Può facilmente allontanarsi da quel numero ed è completamente influenzato dal tipo di collegamento e dalla metrica della distanza. Quando si esegue un'analisi approfondita dei cluster, si consiglia di guardare i dendrogrammi con collegamenti e metriche diverse e di guardare i risultati generati con le prime tre righe in cui i cluster hanno la maggiore distanza tra loro.

Implementazione di un clustering gerarchico agglomerato

Utilizzo dei dati originali

Finora abbiamo calcolato il numero suggerito di cluster per il nostro set di dati che conferma la nostra analisi iniziale e la nostra analisi PCA. Ora possiamo creare il nostro modello di clustering gerarchico agglomerativo utilizzando Scikit-Learn AgglomerativeClustering e scopri le etichette dei punti marketing con labels_:

from sklearn.cluster import AgglomerativeClustering

clustering_model = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model.fit(selected_data)
clustering_model.labels_

Questo risulta in:

array([4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3,
       4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 1,
       4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 0, 2, 0, 2,
       1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2])

Abbiamo studiato molto per arrivare a questo punto. E cosa significano queste etichette? Qui, abbiamo ogni punto dei nostri dati etichettato come un gruppo da 0 a 4:

data_labels = clustering_model.labels_
sns.scatterplot(x='Annual Income (k$)', 
                y='Spending Score (1-100)', 
                data=selected_data, 
                hue=data_labels,
                pallete="rainbow").set_title('Labeled Customer Data')

img

Questi sono i nostri dati raggruppati finali. Puoi vedere i punti dati codificati a colori sotto forma di cinque cluster.

I punti dati in basso a destra (etichetta: 0, punti dati viola) appartengono ai clienti con stipendi alti ma spesa bassa. Questi sono i clienti che spendono i loro soldi con attenzione.

Allo stesso modo, i clienti in alto a destra (etichetta: 2, punti dati verdi), sono i clienti con stipendi alti e spese elevate. Questi sono i tipi di clienti a cui le aziende si rivolgono.

I clienti nel mezzo (etichetta: 1, punti dati blu) sono quelli con reddito medio e spesa media. Rientrano in questa categoria il maggior numero di clienti. Le aziende possono anche prendere di mira questi clienti dato che sono in gran numero.

I clienti in basso a sinistra (etichetta: 4, rosso) sono i clienti che hanno stipendi bassi e poca spesa, potrebbero essere attratti dall'offerta di promozioni.

E infine i clienti in alto a sinistra (etichetta: 3, punti dati arancioni) sono quelli ad alto reddito e bassa spesa, che sono idealmente presi di mira dal marketing.

Utilizzo del risultato della PCA

Se fossimo in uno scenario diverso, in cui dovessimo ridurre la dimensionalità dei dati. Potremmo anche tracciare facilmente i risultati PCA raggruppati. Ciò può essere fatto creando un altro modello di clustering agglomerato e ottenendo un'etichetta dati per ogni componente principale:

clustering_model_pca = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model_pca.fit(pcs)

data_labels_pca = clustering_model_pca.labels_

sns.scatterplot(x=pc1_values, 
                y=pc2_values,
                hue=data_labels_pca,
                palette="rainbow").set_title('Labeled Customer Data Reduced with PCA')

img

Osserva che entrambi i risultati sono molto simili. La differenza principale è che il primo risultato con i dati originali è molto più facile da spiegare. È chiaro che i clienti possono essere divisi in cinque gruppi in base al reddito annuo e al punteggio di spesa. Mentre, nell'approccio PCA, prendiamo in considerazione tutte le nostre funzionalità, per quanto possiamo guardare alla varianza spiegata da ciascuna di esse, questo è un concetto più difficile da comprendere, specialmente quando si fa riferimento a un dipartimento di marketing.

Meno dobbiamo trasformare i nostri dati, meglio è.

Se si dispone di un set di dati molto ampio e complesso in cui è necessario eseguire una riduzione della dimensionalità prima del raggruppamento, provare ad analizzare le relazioni lineari tra ciascuna delle funzionalità e i relativi residui per eseguire il backup dell'uso di PCA e migliorare la spiegabilità del processo. Creando un modello lineare per coppia di caratteristiche, sarai in grado di capire come interagiscono le caratteristiche.

Se il volume dei dati è così grande, diventa impossibile tracciare le coppie di caratteristiche, selezionare un campione dei tuoi dati, il più equilibrato e vicino possibile alla distribuzione normale ed eseguire prima l'analisi sul campione, capirlo, perfezionarlo it – e applicarlo successivamente all'intero set di dati.

Puoi sempre scegliere diverse tecniche di visualizzazione del clustering in base alla natura dei tuoi dati (lineari, non lineari) e combinarle o testarle tutte se necessario.

Conclusione

La tecnica di clustering può essere molto utile quando si tratta di dati senza etichetta. Poiché la maggior parte dei dati nel mondo reale non è etichettata e l'annotazione dei dati ha costi più elevati, le tecniche di clustering possono essere utilizzate per etichettare i dati senza etichetta.

In questa guida abbiamo portato un vero problema di data science, dal momento che le tecniche di clustering sono largamente utilizzate nell'analisi di marketing (e anche nell'analisi biologica). Abbiamo anche spiegato molti dei passaggi dell'indagine per arrivare a un buon modello di clustering gerarchico e come leggere i dendrogrammi e ci siamo chiesti se la PCA sia un passaggio necessario. Il nostro obiettivo principale è quello di coprire alcune delle insidie ​​e dei diversi scenari in cui possiamo trovare il clustering gerarchico.

Buon raggruppamento!

Timestamp:

Di più da Impilamento