Ghid definitiv pentru clusterizarea ierarhică cu Python și Scikit-Learn PlatoBlockchain Data Intelligence. Căutare verticală. Ai.

Ghid definitiv pentru gruparea ierarhică cu Python și Scikit-Learn

Introducere

În acest ghid, ne vom concentra pe implementarea Algoritmul de grupare ierarhică cu Scikit-Learn pentru a rezolva o problemă de marketing.

După ce ați citit ghidul, veți înțelege:

  • Când să aplicați Clusteringul Ierarhic
  • Cum să vizualizați setul de date pentru a înțelege dacă este potrivit pentru grupare
  • Cum să preprocesați caracteristicile și să proiectați noi funcții pe baza setului de date
  • Cum se reduce dimensionalitatea setului de date folosind PCA
  • Cum să utilizați și să citiți o dendrogramă pentru a separa grupuri
  • Care sunt diferitele metode de conectare și metrici de distanță aplicate dendrogramelor și algoritmilor de grupare
  • Care sunt strategiile de grupare aglomerativă și divizionară și cum funcționează acestea
  • Cum se implementează clusteringul ierarhic aglomerativ cu Scikit-Learn
  • Care sunt cele mai frecvente probleme atunci când aveți de-a face cu algoritmii de grupare și cum să le rezolvați

Notă: Puteți descărca blocnotesul care conține tot codul din acest ghid aici.

motivaţia

Imaginați-vă un scenariu în care faceți parte dintr-o echipă de știință a datelor care interacționează cu departamentul de marketing. Marketingul adună date despre cumpărăturile clienților de ceva vreme și aceștia doresc să înțeleagă, pe baza datelor colectate, dacă există asemănări între clienți. Aceste asemănări împart clienții în grupuri, iar existența unor grupuri de clienți ajută la direcționarea campaniilor, promoțiilor, conversiilor și construirea unor relații mai bune cu clienții.

Există vreo modalitate prin care ați putea ajuta să determinați care clienți sunt similari? Câți dintre ei aparțin aceluiași grup? Și câte grupuri diferite există?

O modalitate de a răspunde la aceste întrebări este folosirea a clustering algoritm, cum ar fi K-Means, DBSCAN, Hierarchical Clustering, etc. În termeni generali, algoritmii de clustering găsesc asemănări între punctele de date și le grupează.

În acest caz, datele noastre de marketing sunt destul de mici. Avem informații despre doar 200 de clienți. Având în vedere echipa de marketing, este important să le putem explica în mod clar cum au fost luate deciziile în funcție de numărul de clustere, explicându-le, prin urmare, cum funcționează de fapt algoritmul.

Deoarece datele noastre sunt mici și explicabilitatea este un factor major, putem face pârghie Clusterizarea ierarhică Pentru a rezolva această problemă. Acest proces este cunoscut și ca Analiza de grupare ierarhică (HCA).

Unul dintre avantajele HCA este că este interpretabil și funcționează bine pe seturi de date mici.

Un alt lucru de luat în considerare în acest scenariu este că HCA este un nesupravegheați algoritm. Când grupăm datele, nu vom avea o modalitate de a verifica dacă identificăm corect că un utilizator aparține unui anumit grup (nu cunoaștem grupurile). Nu există etichete cu care să comparăm rezultatele noastre. Dacă am identificat grupurile corect, aceasta va fi ulterior confirmată de către departamentul de marketing pe o bază de zi cu zi (măsurată prin valori precum ROI, rate de conversie etc.).

Acum că am înțeles problema pe care încercăm să o rezolvăm și cum să o rezolvăm, putem începe să aruncăm o privire asupra datelor noastre!

Scurtă analiză exploratorie a datelor

Notă: Puteți descărca setul de date folosit în acest ghid aici.

După descărcarea setului de date, observați că este un CSV (valori separate prin virgulă) fișier numit shopping-data.csv. Pentru a facilita explorarea și manipularea datelor, le vom încărca într-un DataFrame folosind Pandas:

import pandas as pd


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

Marketingul a spus că a strâns 200 de înregistrări ale clienților. Putem verifica dacă datele descărcate sunt complete cu 200 de rânduri folosind shape atribut. Ne va spune câte rânduri și, respectiv, coloane avem:

customer_data.shape

Rezultă:

(200, 5)

Grozav! Datele noastre sunt complete cu 200 de rânduri (înregistrările clienților) și avem și 5 coloane (Caracteristici). Pentru a vedea ce caracteristici a colectat departamentul de marketing de la clienți, putem vedea numele coloanelor cu columns atribut. Pentru a face asta, executați:

customer_data.columns

Scriptul de mai sus returnează:

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

Aici, vedem că marketingul a generat a CustomerID, a adunat Genre, Age, Annual Income (în mii de dolari) și a Spending Score mergând de la 1 la 100 pentru fiecare dintre cei 200 de clienți. Când li s-a cerut lămuriri, ei au spus că valorile din Spending Score coloana semnifică cât de des o persoană cheltuiește bani într-un mall pe o scară de la 1 la 100. Cu alte cuvinte, dacă un client are un scor 0, această persoană nu cheltuiește niciodată bani, iar dacă scorul este 100, tocmai am observat cel mai mare cheltuitor.

Să aruncăm o privire rapidă asupra distribuției acestui scor pentru a inspecta obiceiurile de cheltuieli ale utilizatorilor din setul nostru de date. Acolo sunt panda hist() metoda vine în ajutor:

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

img

Privind histogramă, vedem că peste 35 de clienți au scoruri între 40 și 60, atunci mai puțin de 25 au scoruri între 70 și 80. Deci majoritatea clienților noștri sunt cheltuitori echilibrați, urmat de cheltuitori moderati până la mari. De asemenea, putem vedea că există o linie după 0, în stânga distribuției și o altă linie înainte de 100, în dreapta distribuției. Aceste spații goale înseamnă probabil că distribuția nu conține non-cheltuitoare, care ar avea un scor de 0, și că, de asemenea, nu există cheltuitori mari cu un scor de 100.

Pentru a verifica dacă acest lucru este adevărat, ne putem uita la valorile minime și maxime ale distribuției. Aceste valori pot fi găsite cu ușurință ca parte a statisticilor descriptive, așa că putem folosi describe() metodă pentru a înțelege alte distribuții de valori numerice:


customer_data.describe().transpose()

Acest lucru ne va oferi un tabel din care putem citi distribuțiile altor valori ale setului nostru de date:

 						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

Ipoteza noastră este confirmată. The min valoarea Spending Score is 1 iar maximul este 99. Deci nu avem 0 or 100 scor cheltuitori. Să aruncăm apoi o privire la celelalte coloane ale transpusului describe masa. Când se uită la mean și std coloane, putem vedea că pentru Age il mean is 38.85 si std este de aproximativ 13.97. La fel se întâmplă și pentru Annual Income, Cu un mean of 60.56 și std 26.26, Și pentru Spending Score cu mean of 50 și std of 25.82. Pentru toate caracteristicile, mean este departe de abaterea standard, ceea ce indică datele noastre au o variabilitate mare.

Pentru a înțelege mai bine cum variază datele noastre, să reprezentăm un grafic Annual Income distribuție:

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

Care ne va oferi:

img

Observați în histogramă că majoritatea datelor noastre, peste 35 de clienți, sunt concentrate în apropierea numărului 60, pe nostru mean, pe axa orizontală. Dar ce se întâmplă când ne îndreptăm spre capetele distribuției? Când mergem spre stânga, de la media de 60.560 USD, următoarea valoare pe care o vom întâlni este de 34.300 USD – media (60.560 USD) minus variația standard (26.260 USD). Dacă mergem mai departe la stânga distribuției noastre de date, se aplică o regulă similară, scădem variația standard (26.260 USD) din valoarea curentă (34.300 USD). Prin urmare, vom întâlni o valoare de 8.040 USD. Observați cum datele noastre au trecut rapid de la 60 USD la 8 USD. Este „sărit” de 26.260 USD de fiecare dată – variind foarte mult și de aceea avem o variabilitate atât de mare.

img

Variabilitatea și dimensiunea datelor sunt importante în analiza grupării, deoarece măsurătorile distanței ale majorității algoritmilor de grupare sunt sensibile la mărimile datelor. Diferența de dimensiune poate modifica rezultatele grupării făcând un punct să pară mai aproape sau mai îndepărtat de altul decât este în realitate, distorsionând gruparea reală a datelor.

Până acum, am văzut forma datelor noastre, unele dintre distribuțiile lor și statisticile descriptive. Cu Pandas, putem, de asemenea, lista tipurile noastre de date și să vedem dacă toate cele 200 de rânduri sunt completate sau au unele null valori:

customer_data.info()

Rezultă:

<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

Aici, putem vedea că nu există null valorile din date și că avem o singură coloană categorială – Genre. În această etapă, este important să avem în vedere ce caracteristici par interesante să fie adăugate modelului de clustering. Dacă dorim să adăugăm coloana Gen la modelul nostru, va trebui să îi transformăm valorile din categoric la numeric.

Să vedem cum Genre este completată aruncând o privire rapidă la primele 5 valori ale datelor noastre:

customer_data.head() 

Rezultă:

    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

Se pare că are doar Female și Male categorii. Putem fi siguri de asta aruncând o privire asupra valorilor sale unice cu unique:

customer_data['Genre'].unique()

Acest lucru confirmă presupunerea noastră:

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

Până acum, știm că avem doar două genuri, dacă intenționăm să folosim această funcție pe modelul nostru, Male ar putea fi transformat în 0 și Female la 1. De asemenea, este important să verificați proporția dintre genuri, pentru a vedea dacă sunt echilibrate. Putem face asta cu value_counts() metoda și argumentul ei normalize=True pentru a arăta procentul dintre Male și Female:

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

Acest rezultat:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

Avem 56% dintre femei în setul de date și 44% dintre bărbați. Diferența dintre ele este de doar 16%, iar datele noastre nu sunt 50/50, dar sunt suficient de echilibrat să nu provoace probleme. Dacă rezultatele au fost 70/30, 60/40, atunci ar fi fost nevoie fie de a colecta mai multe date, fie de a folosi un fel de tehnică de creștere a datelor pentru a face acest raport mai echilibrat.

Până acum, toate caracteristicile dar Age, au fost explorate pe scurt. In ceea ce priveste Age, de obicei este interesant să-l împărțiți în coșuri pentru a putea segmenta clienții în funcție de grupele de vârstă ale acestora. Dacă facem asta, ar trebui să transformăm categoriile de vârstă într-un singur număr înainte de a le adăuga la modelul nostru. Astfel, în loc să folosim categoria 15-20 de ani, am număra câți clienți sunt în 15-20 categorie, iar acesta ar fi un număr într-o nouă coloană numită 15-20.

Indicații: În acest ghid, prezentăm doar o scurtă analiză exploratorie a datelor. Dar poți merge mai departe și ar trebui să mergi mai departe. Puteți vedea dacă există diferențe de venit și diferențe de punctaj în funcție de gen și vârstă. Acest lucru nu numai că îmbogățește analiza, dar duce la rezultate mai bune ale modelului. Pentru a aprofunda analiza exploratorie a datelor, consultați capitolul EDA din „Predicție practică pentru prețul casei – Învățare automată în Python Proiect ghidat.

După ce am făcut presupuneri despre ceea ce s-ar putea face atât cu categoric – sau categoric să fie – Genre și Age coloane, să aplicăm ceea ce s-a discutat.

Codificarea variabilelor și ingineria caracteristicilor

Să începem prin a împărți Age în grupuri care variază în 10, astfel încât avem 20-30, 30-40, 40-50 și așa mai departe. Întrucât cel mai tânăr client al nostru are 15 ani, putem începe la 15 ani și se termină la 70, care este vârsta celui mai în vârstă client din date. Începând cu 15 și terminând la 70, am avea intervale de 15-20, 20-30, 30-40, 40-50, 50-60 și 60-70.

A grupa sau bin Age valorile în aceste intervale, putem folosi Pandas cut() metodă de a le tăia în coșuri și apoi de a atribui recipientele unui nou Age Groups coloană:

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'] 

Rezultă:

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]]

Observați că atunci când ne uităm la valorile coloanei, există și o linie care specifică că avem 6 categorii și afișează toate intervalele de date binate. În acest fel, am clasificat datele noastre numerice anterior și am creat un nou Age Groups caracteristică.

Și câți clienți avem în fiecare categorie? Putem ști rapid asta prin gruparea coloanei și numărarea valorilor cu groupby() și count():

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

Rezultă:

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

Este ușor de observat că majoritatea clienților au între 30 și 40 de ani, urmați de clienții între 20 și 30 de ani și apoi clienții între 40 și 50 de ani. Aceasta este o informație bună și pentru departamentul de Marketing.

În acest moment, avem două variabile categoriale, Age și Genre, pe care trebuie să le transformăm în numere pentru a le putea folosi în modelul nostru. Există multe moduri diferite de a face această transformare – vom folosi Panda get_dummies() metodă care creează o nouă coloană pentru fiecare interval și gen și apoi umple valorile acesteia cu 0 și 1 - acest tip de operație se numește codificare one-hot. Să vedem cum arată:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Acest lucru ne va oferi o previzualizare a tabelului rezultat:

img

Cu ieșirea, este ușor să vedeți că coloana Genre a fost împărțit în coloane - Genre_Female și Genre_Male. Când clientul este femeie, Genre_Female este egal cu 1, iar când clientul este bărbat, este egal 0.

De asemenea, Age Groups coloana a fost împărțită în 6 coloane, câte una pentru fiecare interval, cum ar fi Age Groups_(15, 20], Age Groups_(20, 30], si asa mai departe. În același mod ca Genre, când clientul are 18 ani, the Age Groups_(15, 20] valoarea este 1 iar valoarea tuturor celorlalte coloane este 0.

avantaj de codificare one-hot este simplitatea în reprezentarea valorilor coloanei, este simplu de înțeles ce se întâmplă – în timp ce dezavantaj este că acum am creat 8 coloane suplimentare, pentru a rezuma cu coloanele pe care le aveam deja.

avertizare: Dacă aveți un set de date în care numărul de coloane codificate one-hot depășește numărul de rânduri, cel mai bine este să utilizați o altă metodă de codificare pentru a evita problemele legate de dimensionalitatea datelor.

Codificarea one-hot adaugă, de asemenea, 0-uri la datele noastre, făcându-le mai rare, ceea ce poate fi o problemă pentru unii algoritmi care sunt sensibili la raritatea datelor.

Pentru nevoile noastre de clustering, codarea one-hot pare să funcționeze. Dar putem reprezenta datele pentru a vedea dacă există într-adevăr grupuri distincte pe care să le grupăm.

Trasarea de bază și reducerea dimensionalității

Setul nostru de date are 11 coloane și există câteva moduri prin care putem vizualiza acele date. Prima este prin a-l reprezenta în 10 dimensiuni (noroc cu asta). Zece pentru că Customer_ID coloana nu este luată în considerare. Al doilea este prin reprezentarea grafică a caracteristicilor noastre numerice inițiale, iar al treilea este prin transformarea celor 10 caracteristici ale noastre în 2 - prin urmare, efectuând o reducere a dimensionalității.

Trasarea fiecărei perechi de date

Deoarece trasarea a 10 dimensiuni este puțin imposibilă, vom opta pentru a doua abordare - vom reprezenta caracteristicile noastre inițiale. Putem alege două dintre ele pentru analiza noastră de grupare. O modalitate prin care putem vedea toate perechile noastre de date combinate este cu un Seaborn pairplot():

import seaborn as sns


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

sns.pairplot(customer_data)

Care afișează:

img

Dintr-o privire, putem observa diagramele de dispersie care par să aibă grupuri de date. Unul care pare interesant este graficul de dispersie care se combină Annual Income și Spending Score. Observați că nu există o separare clară între alte diagrame de dispersie variabile. Cel mult, putem spune că există două concentrații distincte de puncte în Spending Score vs Age diagramă de dispersie.

Ambele diagrame de dispersie constând din Annual Income și Spending Score sunt în esență aceleași. O putem vedea de două ori deoarece axa x și y au fost schimbate. Aruncând o privire la oricare dintre ele, putem vedea ceea ce par a fi cinci grupuri diferite. Să reprezentăm doar acele două caracteristici cu un Seaborn scatterplot() pentru a arunca o privire mai atenta:

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

img

Privind mai atent, putem distinge cu siguranță 5 grupuri diferite de date. Se pare că clienții noștri pot fi grupați în funcție de cât câștigă într-un an și cât cheltuiesc. Acesta este un alt punct relevant în analiza noastră. Este important să luăm în considerare doar două caracteristici pentru a ne grupa clienții. Orice altă informație pe care o avem despre ei nu intră în ecuație. Acest lucru dă sens analizei – dacă știm cât câștigă și cheltuiește un client, putem găsi cu ușurință asemănările de care avem nevoie.

img

Grozav! Până acum, avem deja două variabile pentru a ne construi modelul. Pe lângă ceea ce reprezintă, face modelul mai simplu, parcimonios și mai explicabil.

Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!

Notă: Știința datelor favorizează de obicei abordări cât mai simple posibil. Nu numai pentru că este mai ușor de explicat pentru business, ci și pentru că este mai direct – cu 2 caracteristici și un model explicabil, este clar ce face modelul și cum funcționează.

Trasarea datelor după utilizarea PCA

Se pare că a doua noastră abordare este probabil cea mai bună, dar să aruncăm o privire și la a treia noastră abordare. Poate fi util atunci când nu putem trasa datele deoarece au prea multe dimensiuni sau când nu există concentrații de date sau separare clară în grupuri. Când apar acele situații, se recomandă să încercați să reduceți dimensiunile datelor cu o metodă numită Analiza componentelor principale (PCA).

Notă: Majoritatea oamenilor folosesc PCA pentru reducerea dimensionalității înainte de vizualizare. Există și alte metode care ajută la vizualizarea datelor înainte de grupare, cum ar fi Clustering spațial bazat pe densitate a aplicațiilor cu zgomot (DBSCAN) și Hărți cu auto-organizare (SOM) gruparea. Ambii sunt algoritmi de grupare, dar pot fi utilizați și pentru vizualizarea datelor. Deoarece analiza grupării nu are un standard de aur, este important să se compare diferite vizualizări și diferiți algoritmi.

PCA va reduce dimensiunile datelor noastre încercând în același timp să păstreze cât mai mult posibil din informațiile sale. Să ne facem mai întâi o idee despre cum funcționează PCA și apoi putem alege la câte dimensiuni de date vom reduce datele.

Pentru fiecare pereche de caracteristici, PCA vede dacă valorile mai mari ale unei variabile corespund cu valorile mai mari ale celeilalte variabile și face același lucru pentru valorile mai mici. Deci, în esență, calculează cât de mult variază valorile caracteristicilor una față de cealaltă - noi numim asta lor covarianță. Aceste rezultate sunt apoi organizate într-o matrice, obținându-se a matricea de covarianță.

După obținerea matricei de covarianță, PCA încearcă să găsească o combinație liniară de caracteristici care o explică cel mai bine – se potrivește modelelor liniare până când îl identifică pe cel care explică maxim cantitatea de variație.

notițe: PCA este o transformare liniară, iar liniaritatea este sensibilă la scara datelor. Prin urmare, PCA funcționează cel mai bine atunci când toate valorile datelor sunt la aceeași scară. Acest lucru se poate face prin scăderea coloanei însemna din valorile sale și împărțind rezultatul la abaterea sa standard. Asta se numeste standardizarea datelor. Înainte de a utiliza PCA, asigurați-vă că datele sunt scalate! Dacă nu sunteți sigur cum, citiți „Scalarea datelor cu funcții cu Scikit-Learn pentru învățarea automată în Python”!

Cu cea mai bună linie (combinație liniară) găsită, PCA primește direcțiile axelor sale, numite vectori proprii, și coeficienții săi liniari, valori proprii. Combinația de vectori proprii și valori proprii – sau direcțiile și coeficienții axelor – sunt Componentele principale a PCA. Și atunci putem alege numărul nostru de dimensiuni pe baza variației explicate a fiecărei caracteristici, înțelegând ce componente principale dorim să păstrăm sau să renunțăm în funcție de varianța pe care o explică.

După obținerea componentelor principale, PCA folosește vectorii proprii pentru a forma un vector de caracteristici care reorientează datele de la axele originale către cele reprezentate de componentele principale – așa se reduc dimensiunile datelor.

Notă: Un detaliu important de luat în considerare aici este că, datorită naturii sale lineare, PCA va concentra cea mai mare parte a variației explicate în primele componente principale. Deci, când ne uităm la variația explicată, de obicei primele două componente vor fi suficiente. Dar asta ar putea induce în eroare în unele cazuri – așa că încercați să continuați să comparați diferiți diagrame și algoritmi atunci când grupați pentru a vedea dacă au rezultate similare.

Înainte de a aplica PCA, trebuie să alegem între Age coloana sau Age Groups coloane din datele noastre anterior codificate one-hot. Deoarece ambele coloane reprezintă aceleași informații, introducerea acesteia de două ori afectează variația datelor noastre. Dacă Age Groups coloana este aleasă, pur și simplu eliminați Age coloană folosind Panda drop() metoda și reatribuiți-o către customer_data_oh variabilă:

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

Acum datele noastre au 10 coloane, ceea ce înseamnă că putem obține o componentă principală cu coloană și putem alege câte dintre ele vom folosi, măsurând cât de mult introducerea unei noi dimensiuni explică mai mult varianța datelor noastre.

Să facem asta cu Scikit-Learn PCA. Vom calcula varianța explicată a fiecărei dimensiuni, dată de explained_variance_ratio_ , și apoi uitați-vă la suma lor cumulată cu cumsum() :

from sklearn.decomposition import PCA

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

Varianțele noastre explicate cumulate sunt:

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

Putem vedea că prima dimensiune explică 50% din date, iar atunci când sunt combinate cu cea de-a doua dimensiune, ele explică 99% la sută. Aceasta înseamnă că primele 2 dimensiuni explică deja 99% din datele noastre. Deci putem aplica un PCA cu 2 componente, obținem componentele noastre principale și le putem reprezenta grafic:

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

Graficul de date după PCA este foarte similar cu graficul care utilizează doar două coloane de date fără PCA. Observați că punctele care formează grupuri sunt mai apropiate și puțin mai concentrate după PCA decât înainte.

img

Vizualizarea structurii ierarhice cu dendrograme

Până acum, am explorat datele, coloanele categorice codificate one-hot, am decis care coloane sunt potrivite pentru grupare și am redus dimensionalitatea datelor. Graficele indică faptul că avem 5 clustere în datele noastre, dar există și o altă modalitate de a vizualiza relațiile dintre punctele noastre și de a ajuta la determinarea numărului de clustere - prin crearea unui dendrograma (de obicei scris greșit ca dendogramă). dendro mijloace copac în latină.

dendrograma este rezultatul legăturii punctelor dintr-un set de date. Este o reprezentare vizuală a procesului de grupare ierarhică. Și cum funcționează procesul de grupare ierarhică? Ei bine... depinde – probabil un răspuns pe care l-ați auzit deja multe în Data Science.

Înțelegerea grupării ierarhice

Cand Algoritmul de grupare ierarhică (HCA) începe să lege punctele și să găsească grupuri, mai întâi poate împărți punctele în 2 grupuri mari și apoi împărțiți fiecare dintre aceste două grupuri în 2 grupuri mai mici, având 4 grupuri în total, care este dezbinare și de sus în jos abordare.

Alternativ, poate face opusul - poate analiza toate punctele de date, poate găsi 2 puncte care sunt mai aproape unul de celălalt, le poate lega și apoi găsi alte puncte care sunt cele mai apropiate de acele puncte legate și continuă să construiți cele 2 grupuri de la de jos în sus. Care este aglomerativ abordare pe care o vom dezvolta.

Pași pentru a realiza clusterizarea ierarhică aglomerativă

Pentru a clarifica abordarea aglomerativă, există pași ai Clustering ierarhic aglomerativ (AHC) algoritm:

  1. La început, tratați fiecare punct de date ca un grup. Prin urmare, numărul de clustere la început va fi K – în timp ce K este un număr întreg care reprezintă numărul de puncte de date.
  2. Formați un cluster prin unirea celor mai apropiate două puncte de date, rezultând clustere K-1.
  3. Formați mai multe clustere prin unirea celor mai apropiate două clustere, rezultând clustere K-2.
  4. Repetați cei trei pași de mai sus până când se formează un grup mare.

notițe: Pentru simplificare, spunem „două cele mai apropiate” puncte de date în pașii 2 și 3. Dar există mai multe moduri de a lega punctele, așa cum vom vedea în curând.

If you invert the steps of the ACH algorithm, going from 4 to 1 – those would be the steps to *Clustering ierarhic divizibil (DHC)*.

Observați că HCA-urile pot fi fie divizoare și de sus în jos, fie aglomerative și de jos în sus. Abordarea DHC de sus în jos funcționează cel mai bine atunci când aveți mai puține clustere, dar mai mari, prin urmare este mai costisitoare din punct de vedere computațional. Pe de altă parte, abordarea AHC de jos în sus este potrivită atunci când aveți multe clustere mai mici. Este mai simplu din punct de vedere computațional, mai folosit și mai disponibil.

Notă: Fie de sus în jos, fie de jos în sus, reprezentarea dendrogramă a procesului de grupare va începe întotdeauna cu o împărțire în două și va sfârși cu fiecare punct individual discriminat, odată ce structura sa de bază este a unui arbore binar.

Să trasăm dendrograma datelor clienților noastre pentru a vizualiza relațiile ierarhice ale datelor. De data aceasta, vom folosi scipy bibliotecă pentru a crea dendrograma pentru setul nostru de date:

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()

Ieșirea scriptului arată astfel:

img

În scriptul de mai sus, am generat clusterele și subclusterele cu punctele noastre, am definit cum se vor lega punctele noastre (prin aplicarea ward metoda) și modul de măsurare a distanței dintre puncte (prin folosirea euclidean metric).

Cu graficul dendrogramei, procesele descrise ale DHC și AHC pot fi vizualizate. Pentru a vizualiza abordarea de sus în jos, începeți din partea de sus a dendrogramei și mergeți în jos și faceți opusul, pornind în jos și deplasându-vă în sus pentru a vizualiza abordarea de jos în sus.

Metode de conectare

Există multe alte metode de conectare, înțelegând mai multe despre modul în care funcționează, veți putea alege cea potrivită nevoilor dvs. În plus, fiecare dintre ele va da rezultate diferite atunci când este aplicat. Nu există o regulă fixă ​​în analiza grupării, dacă este posibil, studiați natura problemei pentru a vedea care se potrivește cel mai bine, testați diferite metode și inspectați rezultatele.

Unele dintre metodele de conectare sunt:

  • Legătura unică: denumit și ca Cel mai apropiat vecin (NN). Distanța dintre clustere este definită de distanța dintre membrii lor cei mai apropiați.

img

  • Legătura completă: denumit și ca Cel mai îndepărtat vecin (FN), Algoritmul punctului cel mai îndepărtat, Sau Algoritmul Voor Hees. Distanța dintre clustere este definită de distanța dintre membrii lor cei mai îndepărtați. Această metodă este costisitoare din punct de vedere al calculului.

img

  • Legătura medie: de asemenea cunoscut ca si UPGMA (Metoda grupului de perechi neponderat cu medie aritmetică). Procentul din numărul de puncte al fiecărui cluster este calculat în raport cu numărul de puncte ale celor două clustere dacă acestea au fost îmbinate.

img

  • Legătura ponderată: de asemenea cunoscut ca si WPGMA (Metoda grupului de perechi ponderate cu medie aritmetică). Punctele individuale ale celor două clustere contribuie la distanța agregată dintre un cluster mai mic și unul mai mare.
  • Legătura centroidă: denumit și ca UPGMC (Metoda grupului de perechi neponderat folosind centroizi). Un punct definit de media tuturor punctelor (centroid) este calculat pentru fiecare cluster, iar distanța dintre clustere este distanța dintre centroizii lor respectivi.

img

  • Legătura secției: De asemenea cunoscut ca si MISSQ (Creștere minimă a sumei pătratelor). Specifică distanța dintre două clustere, calculează eroarea sumei pătratelor (ESS) și alege succesiv următoarele clustere pe baza ESS mai mică. Metoda lui Ward urmărește să minimizeze creșterea ESS la fiecare pas. Prin urmare, minimizarea erorilor.

img

Măsuri de distanță

Pe lângă conectare, putem specifica și unele dintre cele mai utilizate valori ale distanței:

  • euclidiană: denumit și ca pitagoreică sau linie dreaptă distanţă. Calculează distanța dintre două puncte din spațiu, măsurând lungimea unui segment de linie care trece între ele. Folosește teorema lui Pitagora și rezultatul este valoarea distanței (C) a ecuației:

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

  • Manhattan: numit si Bloc, taxi distanţă. Este suma diferențelor absolute dintre măsurile în toate dimensiunile a două puncte. Dacă acele dimensiuni sunt două, este analog cu a face o dreapta și apoi la stânga atunci când mergi un bloc.

img

  • Minkowski: este o generalizare atât a distanțelor euclidiene, cât și a celor Manhattan. Este o modalitate de a calcula distanțe pe baza diferențelor absolute față de ordinea metricii Minkowski p. Deși este definit pentru orice p> 0, este rar folosit pentru alte valori decât 1, 2 și ∞ (infinit). Distanța Minkowski este aceeași cu distanța Manhattan când p = 1, și la fel ca distanța euclidiană când p = 2.

$$
Dleft(X,Yright) = left(sum_{i=1}^n |x_i-y_i|^pright)^{frac{1}{p}}
$$

img

  • Cebîșev: de asemenea cunoscut ca si Tablă de şah distanţă. Este cazul extrem al distanței Minkowski. Când folosim infinitul ca valoare a parametrului p (p = ∞), ajungem la o metrică care definește distanța ca diferența absolută maximă dintre coordonate.
  • cosinus: este distanța cosinus unghiular dintre două secvențe de puncte sau vectori. Similitudinea cosinus este produsul scalar al vectorilor împărțit la produsul lungimii lor.
  • Jaccard: măsoară asemănarea dintre seturi finite de puncte. Se definește ca numărul total de puncte (cardinalitate) din punctele comune din fiecare set (intersecție), împărțit la numărul total de puncte (cardinalitate) din totalul punctelor ambelor seturi (unire).
  • Jensen-Shannon: bazat pe divergența Kullback-Leibler. Ea ia în considerare distribuțiile de probabilitate ale punctelor și măsoară similitudinea dintre aceste distribuții. Este o metodă populară de teorie și statistică a probabilităților.

Am ales Cartier și euclidiană pentru dendrogramă deoarece sunt metoda și metrica cel mai des folosită. De obicei, dau rezultate bune, deoarece Ward leagă puncte pe baza minimizării erorilor, iar Euclidean funcționează bine în dimensiuni mai mici.

În acest exemplu, lucrăm cu două caracteristici (coloane) ale datelor de marketing și 200 de observații sau rânduri. Deoarece numărul de observații este mai mare decât numărul de caracteristici (200 > 2), lucrăm într-un spațiu cu dimensiuni reduse.

Când numărul de caracteristici (F) este mai mare decât numărul de observații (N) – scris în mare parte ca f >> N, înseamnă că avem un spațiu dimensional înalt.

Dacă ar fi să includem mai multe atribute, deci avem mai mult de 200 de caracteristici, distanța euclidiană ar putea să nu funcționeze foarte bine, deoarece ar avea dificultăți în măsurarea tuturor distanțelor mici într-un spațiu foarte mare care doar devine mai mare. Cu alte cuvinte, abordarea distanței euclidiene are dificultăți în lucrul cu datele raritate. Aceasta este o problemă care se numește blestemul dimensionalității. Valorile distanței ar deveni atât de mici, de parcă ar fi „diluate” în spațiul mai mare, distorsionate până când ar deveni 0.

Notă: Dacă întâlniți vreodată un set de date cu f >> p, probabil că veți folosi alte valori ale distanței, cum ar fi Mahalanobis distanţă. Alternativ, puteți reduce și dimensiunile setului de date, utilizând Analiza componentelor principale (PCA). Această problemă este frecventă în special atunci când se grupează date de secvențiere biologică.

Am discutat deja despre valorile, legăturile și modul în care fiecare dintre ele poate afecta rezultatele noastre. Să continuăm acum analiza dendrogramei și să vedem cum ne poate oferi o indicație asupra numărului de clustere din setul nostru de date.

Găsirea unui număr interesant de clustere într-o dendrogramă este același lucru cu găsirea celui mai mare spațiu orizontal care nu are linii verticale (spațiul cu cele mai lungi linii verticale). Aceasta înseamnă că există mai multă separare între grupuri.

Putem trasa o linie orizontală care trece prin cea mai mare distanță:

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

După localizarea liniei orizontale, numărăm de câte ori liniile noastre verticale au fost traversate de ea – în acest exemplu, de 5 ori. Deci 5 pare un bun indiciu al numărului de clustere care au cea mai mare distanță între ele.

notițe: Dendrograma ar trebui să fie considerată doar ca referință atunci când este utilizată pentru a alege numărul de clustere. Poate obține cu ușurință acest număr și este complet influențat de tipul de conexiune și metrica distanței. Atunci când se efectuează o analiză aprofundată a clusterului, se recomandă să se analizeze dendrogramele cu diferite legături și metrici și să se analizeze rezultatele generate cu primele trei linii în care clusterele au cea mai mare distanță între ele.

Implementarea unui clustering ierarhic aglomerativ

Utilizarea datelor originale

Până acum am calculat numărul sugerat de clustere pentru setul nostru de date care se coroborează cu analiza noastră inițială și analiza noastră PCA. Acum putem crea modelul nostru de clustering ierarhic aglomerativ folosind Scikit-Learn AgglomerativeClustering si afla etichetele punctelor de marketing cu labels_:

from sklearn.cluster import AgglomerativeClustering

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

Rezultă:

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])

Am investigat multe pentru a ajunge la acest punct. Și ce înseamnă aceste etichete? Aici, avem fiecare punct al datelor noastre etichetat ca un grup de la 0 la 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

Acestea sunt datele noastre finale grupate. Puteți vedea punctele de date cu coduri de culoare sub formă de cinci grupuri.

Punctele de date din dreapta jos (eticheta: 0, puncte de date violet) aparțin clienților cu salarii mari, dar cu cheltuieli mici. Aceștia sunt clienții care își cheltuiesc banii cu grijă.

În mod similar, clienții din dreapta sus (etichetă: 2, puncte de date verzi), sunt clienții cu salarii mari și cheltuieli mari. Acestea sunt tipurile de clienți pe care îi vizează companiile.

Clienții din mijloc (etichetă: 1, puncte de date albastre) sunt cele cu venituri medii și cheltuieli medii. În această categorie aparțin cel mai mare număr de clienți. Companiile pot viza și acești clienți având în vedere faptul că sunt în număr foarte mare.

Clienții din stânga jos (etichetă: 4, roșu) sunt clienții care au salarii mici și cheltuieli mici, aceștia ar putea fi atrași prin oferirea de promoții.

Și, în sfârșit, clienții din stânga sus (etichetă: 3, puncte de date portocalii) sunt cele cu venituri mari și cheltuieli mici, care sunt vizate în mod ideal de marketing.

Folosind rezultatul de la PCA

Dacă am fi într-un scenariu diferit, în care ar fi trebuit să reducem dimensionalitatea datelor. De asemenea, am putea reprezenta cu ușurință rezultatele PCA grupate. Acest lucru se poate realiza prin crearea unui alt model de clustering aglomerativ și obținerea unei etichete de date pentru fiecare componentă principală:

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

Observați că ambele rezultate sunt foarte asemănătoare. Principala diferență este că primul rezultat cu datele originale este mult mai ușor de explicat. Este clar de văzut că clienții pot fi împărțiți în cinci grupuri în funcție de venitul anual și scorul de cheltuieli. În timp ce, în abordarea PCA, luăm în considerare toate caracteristicile noastre, pe cât de mult ne putem uita la variația explicată de fiecare dintre ele, acesta este un concept mai greu de înțeles, mai ales atunci când raportăm la un departament de marketing.

Cu cât trebuie să ne transformăm mai puțin datele, cu atât mai bine.

Dacă aveți un set de date foarte mare și complex în care trebuie să efectuați o reducere a dimensionalității înainte de grupare - încercați să analizați relațiile liniare dintre fiecare dintre caracteristici și reziduurile lor pentru a susține utilizarea PCA și pentru a îmbunătăți explicabilitatea procesului. Făcând un model liniar pe pereche de caracteristici, veți putea înțelege cum interacționează caracteristicile.

Dacă volumul de date este atât de mare, devine imposibil să reprezentați perechile de caracteristici, să selectați un eșantion de date, cât mai echilibrat și cât mai aproape posibil de distribuția normală și să efectuați mai întâi analiza pe eșantion, să o înțelegeți, să o ajustați. it – și aplicați-o mai târziu întregului set de date.

Puteți alege oricând diferite tehnici de vizualizare a grupării în funcție de natura datelor dvs. (liniare, neliniare) și să le combinați sau să le testați pe toate dacă este necesar.

Concluzie

Tehnica de grupare poate fi foarte utilă atunci când vine vorba de date neetichetate. Deoarece majoritatea datelor din lumea reală sunt neetichetate și adnotarea datelor are costuri mai mari, tehnicile de grupare pot fi folosite pentru a eticheta datele neetichetate.

În acest ghid, am adus o problemă reală de știință a datelor, deoarece tehnicile de clustering sunt utilizate în mare măsură în analiza de marketing (și, de asemenea, în analiza biologică). Am explicat, de asemenea, mulți dintre pașii de investigare pentru a ajunge la un model de clustering ierarhic bun și cum să citim dendrogramele și am întrebat dacă PCA este un pas necesar. Obiectivul nostru principal este ca unele dintre capcanele și diferitele scenarii în care putem găsi clustering ierarhic sunt acoperite.

Agrupare fericită!

Timestamp-ul:

Mai mult de la Stackabuse