Definitieve gids voor hiërarchische clustering met Python en Scikit-Learn PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Definitieve gids voor hiërarchische clustering met Python en Scikit-Learn

Introductie

In deze gids zullen we ons concentreren op het implementeren van de Hiërarchisch clusteringsalgoritme met Scikit-Learn om een ​​marketingprobleem op te lossen.

Na het lezen van de gids begrijpt u:

  • Wanneer hiërarchische clustering toepassen?
  • Hoe de dataset te visualiseren om te begrijpen of deze geschikt is voor clustering
  • Functies voorbewerken en nieuwe functies ontwikkelen op basis van de dataset
  • Hoe de dimensionaliteit van de dataset te verminderen met PCA
  • Hoe een dendrogram te gebruiken en te lezen om groepen te scheiden
  • Wat zijn de verschillende koppelingsmethoden en afstandsmetrieken die worden toegepast op dendrogrammen en clusteringalgoritmen?
  • Wat zijn de agglomeratieve en verdelende clusterstrategieën en hoe werken ze?
  • Hoe de Agglomeratieve Hiërarchische Clustering te implementeren met Scikit-Learn
  • Wat zijn de meest voorkomende problemen bij het omgaan met clusteralgoritmen en hoe deze op te lossen?

Opmerking: U kunt het notitieboekje met alle code in deze handleiding downloaden hier.

Motivatie

Stelt u zich een scenario voor waarin u deel uitmaakt van een data science-team dat samenwerkt met de marketingafdeling. Marketing verzamelt al een tijdje winkelgegevens van klanten en ze willen op basis van de verzamelde gegevens begrijpen of die er zijn overeenkomsten tussen klanten. Die overeenkomsten verdelen klanten in groepen en het hebben van klantgroepen helpt bij het targeten van campagnes, promoties, conversies en het opbouwen van betere klantrelaties.

Is er een manier om te bepalen welke klanten vergelijkbaar zijn? Hoeveel van hen behoren tot dezelfde groep? En hoeveel verschillende groepen zijn er?

Een manier om die vragen te beantwoorden is door a clustering algoritme, zoals K-Means, DBSCAN, hiërarchische clustering, enz. In algemene termen vinden clusteringalgoritmen overeenkomsten tussen gegevenspunten en groeperen ze.

In dit geval zijn onze marketinggegevens vrij klein. We hebben informatie over slechts 200 klanten. Gezien het marketingteam is het belangrijk dat we hen duidelijk kunnen uitleggen hoe de beslissingen tot stand zijn gekomen op basis van het aantal clusters, zodat we hen kunnen uitleggen hoe het algoritme eigenlijk werkt.

Omdat onze gegevens klein zijn en verklaarbaarheid een belangrijke factor is, we kunnen gebruikmaken van Hiërarchische clustering om dit probleem op te lossen. Dit proces staat ook bekend als: Hiërarchische Clustering Analyse (HCA).

Een van de voordelen van HCA is dat het interpreteerbaar is en goed werkt op kleine datasets.

Een ander ding om rekening mee te houden in dit scenario is dat HCA een ongecontroleerd algoritme. Bij het groeperen van gegevens hebben we geen manier om te verifiëren dat we correct identificeren dat een gebruiker tot een specifieke groep behoort (we kennen de groepen niet). Er zijn geen labels waarmee we onze resultaten kunnen vergelijken. Als we de groepen correct hebben geïdentificeerd, wordt dit later dagelijks bevestigd door de marketingafdeling (gemeten aan de hand van statistieken zoals ROI, conversiepercentages, enz.).

Nu we het probleem dat we proberen op te lossen hebben begrepen en hoe we het kunnen oplossen, kunnen we onze gegevens gaan bekijken!

Korte verkennende gegevensanalyse

Opmerking: U kunt de dataset die in deze handleiding wordt gebruikt downloaden hier.

Merk na het downloaden van de dataset op dat het een CSV (door komma's gescheiden waarden) bestand genaamd shopping-data.csv. Om het gemakkelijker te maken om de gegevens te verkennen en te manipuleren, laden we deze in een DataFrame Panda's gebruiken:

import pandas as pd


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

Marketing zei dat het 200 klantrecords had verzameld. We kunnen controleren of de gedownloade gegevens compleet zijn met 200 rijen met behulp van de shape attribuut. Het zal ons vertellen hoeveel rijen en kolommen we hebben, respectievelijk:

customer_data.shape

Dit resulteert in:

(200, 5)

Super goed! Onze gegevens zijn compleet met 200 rijen (klantgegevens) en we hebben ook 5 kolommen (Kenmerken). Om te zien welke kenmerken de marketingafdeling van klanten heeft verzameld, kunnen we kolomnamen zien met de columns attribuut. Om dat te doen, voert u uit:

customer_data.columns

Het bovenstaande script retourneert:

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

Hier zien we dat marketing een CustomerID, verzamelde de Genre, Age, Annual Income (in duizenden dollars), en a Spending Score gaande van 1 tot 100 voor elk van de 200 klanten. Toen ze om opheldering vroegen, zeiden ze dat de waarden in de Spending Score kolom geeft aan hoe vaak een persoon geld uitgeeft in een winkelcentrum op een schaal van 1 tot 100. Met andere woorden, als een klant een score van 0 heeft, geeft deze persoon nooit geld uit, en als de score 100 is, hebben we zojuist de hoogste besteding.

Laten we even kijken naar de verdeling van deze score om het bestedingspatroon van gebruikers in onze dataset te bekijken. Dat is waar de Panda's hist() methode komt om te helpen:

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

img

Door naar het histogram te kijken zien we dat meer dan 35 klanten scores hebben tussen 40 en 60, dan hebben minder dan 25 scores tussen 70 en 80. Dus de meeste van onze klanten zijn: evenwichtige bestedingen, gevolgd door matige tot hoge bestedingen. We kunnen ook zien dat er een regel is na 0, links van de verdeling, en nog een regel voor 100, rechts van de verdeling. Deze lege ruimtes betekenen waarschijnlijk dat de distributie geen niet-spenders bevat, wat een score van . zou hebben 0, en dat er ook geen high-spenders zijn met een score van 100.

Om te controleren of dat waar is, kunnen we kijken naar de minimum- en maximumwaarden van de verdeling. Die waarden kunnen gemakkelijk worden gevonden als onderdeel van de beschrijvende statistieken, dus we kunnen de describe() methode om inzicht te krijgen in andere verdelingen van numerieke waarden:


customer_data.describe().transpose()

Dit geeft ons een tabel van waaruit we distributies van andere waarden van onze dataset kunnen lezen:

 						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

Onze hypothese wordt bevestigd. De min waarde van de Spending Score is 1 en het maximum is 99. Dus we hebben niet 0 or 100 besteders scoren. Laten we dan eens kijken naar de andere kolommen van de getransponeerde describe tafel. Bij het kijken naar de mean en std kolommen, dat kunnen we zien voor Age de mean is 38.85 en std ongeveer 13.97. Hetzelfde gebeurt voor Annual Income, Met een mean of 60.56 en std 26.26En voor Spending Score met een mean of 50 en std of 25.82. Voor alle functies is de mean is ver verwijderd van de standaarddeviatie, wat aangeeft: onze gegevens hebben een hoge variabiliteit.

Laten we, om beter te begrijpen hoe onze gegevens variëren, de Annual Income verdeling:

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

Wat ons zal geven:

img

Merk in het histogram op dat de meeste van onze gegevens, meer dan 35 klanten, geconcentreerd zijn in de buurt van het nummer 60, op onze mean, in de horizontale as. Maar wat gebeurt er als we naar de uiteinden van de distributie gaan? Als we naar links gaan, vanaf het gemiddelde van $ 60.560, is de volgende waarde die we tegenkomen $ 34.300 - het gemiddelde ($ 60.560) minus de standaardvariatie ($ 26.260). Als we verder weg gaan naar de linkerkant van onze gegevensdistributie, is een vergelijkbare regel van toepassing, we trekken de standaardvariatie ($ 26.260) af van de huidige waarde ($ 34.300). Daarom komen we een waarde van $ 8.040 tegen. Merk op hoe onze gegevens snel van $ 60 naar $ 8 gingen. Het "springt" elke keer $ 26.260 - veel variërend, en daarom hebben we zo'n hoge variabiliteit.

img

De variabiliteit en de grootte van de gegevens zijn belangrijk bij clusteranalyse omdat afstandsmetingen van de meeste clusteringalgoritmen gevoelig zijn voor gegevensgrootheden. Het verschil in grootte kan de clusterresultaten veranderen door het ene punt dichterbij of verder weg te laten lijken dan het in werkelijkheid is, waardoor de feitelijke groepering van gegevens wordt vervormd.

Tot nu toe hebben we de vorm van onze gegevens, enkele van de distributies en beschrijvende statistieken gezien. Met Panda's kunnen we ook onze gegevenstypen opsommen en zien of al onze 200 rijen gevuld zijn of een aantal hebben null waarden:

customer_data.info()

Dit resulteert 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

Hier kunnen we zien dat er geen null waarden in de gegevens en dat we slechts één categorische kolom hebben - Genre. In dit stadium is het belangrijk dat we in gedachten hebben welke functies interessant lijken om aan het clustermodel toe te voegen. Als we de kolom Genre aan ons model willen toevoegen, moeten we de waarden ervan transformeren van categorisch naar numeriek.

Laten we kijken hoe Genre wordt gevuld door een snelle blik te werpen op de eerste 5 waarden van onze gegevens:

customer_data.head() 

Dit resulteert 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

Het lijkt erop dat het alleen heeft Female en Male categorieën. Daar kunnen we zeker van zijn door de unieke waarden te bekijken met unique:

customer_data['Genre'].unique()

Dit bevestigt onze veronderstelling:

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

Tot nu toe weten we dat we slechts twee genres hebben, als we van plan zijn deze functie op ons model te gebruiken, Male zou kunnen worden omgevormd tot 0 en Female naar 1. Het is ook belangrijk om de verhouding tussen genres te controleren, om te zien of ze in balans zijn. Dat kunnen we doen met de value_counts() methode en zijn argument normalize=True om het percentage weer te geven tussen Male en Female:

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

Dit levert op:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

We hebben 56% van de vrouwen in de dataset en 44% van de mannen. Het verschil tussen hen is slechts 16%, en onze gegevens zijn niet 50/50 maar is gebalanceerd genoeg om geen problemen te veroorzaken. Als de resultaten 70/30, 60/40 waren, was het misschien nodig geweest om meer gegevens te verzamelen of om een ​​of andere techniek voor gegevensvergroting te gebruiken om die verhouding evenwichtiger te maken.

Tot nu toe alle functies behalve Age, zijn kort onderzocht. Wat betreft? Age, is het meestal interessant om het in bakken te verdelen om klanten te kunnen segmenteren op basis van hun leeftijdsgroepen. Als we dat doen, moeten we de leeftijdscategorieën omzetten in één getal voordat we ze aan ons model toevoegen. Op die manier zouden we, in plaats van de categorie 15-20 jaar te gebruiken, tellen hoeveel klanten er zijn in de 15-20 categorie, en dat zou een getal zijn in een nieuwe kolom genaamd 15-20.

Advies: In deze gids presenteren we alleen een korte verkennende data-analyse. Maar je kunt verder gaan en je moet verder gaan. Je kunt zien of er inkomensverschillen zijn en scoreverschillen op basis van genre en leeftijd. Dit verrijkt niet alleen de analyse, maar leidt ook tot betere modelresultaten. Om dieper in te gaan op verkennende data-analyse, bekijk de EDA-hoofdstuk in de “Hands-on voorspelling van huizenprijzen - Machine learning in Python" Begeleid project.

Na gissen over wat er zou kunnen worden gedaan met zowel categorisch - of categorisch te zijn - Genre en Age kolommen, laten we toepassen wat is besproken.

Coderingsvariabelen en functie-engineering

Laten we beginnen met het delen van de Age in groepen die variëren in 10, zodat we 20-30, 30-40, 40-50, enzovoort hebben. Aangezien onze jongste klant 15 is, kunnen we beginnen bij 15 en eindigen bij 70, wat de leeftijd is van de oudste klant in de gegevens. Beginnend bij 15 en eindigend bij 70, zouden we intervallen van 15-20, 20-30, 30-40, 40-50, 50-60 en 60-70 hebben.

Naar groep of bak Age waarden in deze intervallen, kunnen we de Panda's cut() methode om ze in bakken te snijden en de bakken vervolgens toe te wijzen aan een nieuwe Age Groups kolom:

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

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

Merk op dat wanneer we naar de kolomwaarden kijken, er ook een regel is die aangeeft dat we 6 categorieën hebben en alle binned data-intervallen weergeeft. Op deze manier hebben we onze eerder numerieke gegevens gecategoriseerd en een nieuwe Age Groups kenmerk.

En hoeveel klanten hebben we in elke categorie? We kunnen dat snel weten door de kolom te groeperen en de waarden te tellen met groupby() en count():

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

Dit resulteert 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

Het is gemakkelijk te zien dat de meeste klanten tussen de 30 en 40 jaar zijn, gevolgd door klanten tussen de 20 en 30 en dan klanten tussen de 40 en 50. Ook voor de afdeling Marketing is dit goede informatie.

Op dit moment hebben we twee categorische variabelen, Age en Genre, die we in getallen moeten omzetten om ze in ons model te kunnen gebruiken. Er zijn veel verschillende manieren om die transformatie te maken - we zullen de Panda's gebruiken get_dummies() methode die een nieuwe kolom maakt voor elk interval en genre en vervolgens de waarden vult met 0s en 1s - dit soort bewerking wordt genoemd one-hot codering. Laten we eens kijken hoe het eruit ziet:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Dit geeft ons een voorproefje van de resulterende tabel:

img

Met de uitvoer is het gemakkelijk te zien dat de kolom Genre werd opgesplitst in kolommen - Genre_Female en Genre_Male. Als de klant een vrouw is, Genre_Female is gelijk aan 1, en als de klant een man is, is dat gelijk aan 0.

Ook de Age Groups kolom werd opgesplitst in 6 kolommen, één voor elk interval, zoals: Age Groups_(15, 20], Age Groups_(20, 30], enzovoort. Op dezelfde manier als Genre, wanneer de klant 18 jaar oud is, de Age Groups_(15, 20] Waarde is 1 en de waarde van alle andere kolommen is 0.

De voordeel van one-hot codering is de eenvoud bij het weergeven van de kolomwaarden, het is eenvoudig om te begrijpen wat er gebeurt - terwijl de nadeel is dat we nu 8 extra kolommen hebben gemaakt, om samen te vatten met de kolommen die we al hadden.

waarschuwing: Als u een gegevensset hebt waarin het aantal one-hot-gecodeerde kolommen het aantal rijen overschrijdt, kunt u het beste een andere coderingsmethode gebruiken om problemen met de dimensionaliteit van gegevens te voorkomen.

One-hot codering voegt ook nullen toe aan onze gegevens, waardoor deze schaarser worden, wat een probleem kan zijn voor sommige algoritmen die gevoelig zijn voor gegevenssparsity.

Voor onze clusterbehoeften lijkt one-hot codering te werken. Maar we kunnen de gegevens plotten om te zien of er echt verschillende groepen zijn die we kunnen clusteren.

Basis plotten en dimensionaliteitsreductie

Onze dataset heeft 11 kolommen en er zijn enkele manieren waarop we die gegevens kunnen visualiseren. De eerste is door het in 10-dimensies te plotten (veel succes daarmee). tien omdat de Customer_ID kolom wordt niet overwogen. De tweede is door onze initiële numerieke kenmerken te plotten, en de derde is door onze 10 kenmerken om te zetten in 2 - en daarom een ​​dimensionaliteitsreductie uit te voeren.

Elk paar gegevens plotten

Omdat het plotten van 10 dimensies een beetje onmogelijk is, kiezen we voor de tweede benadering - we zullen onze eerste kenmerken plotten. We kunnen er twee kiezen voor onze clusteranalyse. Een manier waarop we al onze dataparen gecombineerd kunnen zien, is met een Seaborn pairplot():

import seaborn as sns


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

sns.pairplot(customer_data)

Welke wordt weergegeven:

img

In één oogopslag kunnen we de scatterplots zien die groepen gegevens lijken te hebben. Een die interessant lijkt, is de scatterplot die combineert Annual Income en Spending Score. Merk op dat er geen duidelijke scheiding is tussen andere variabele scatterplots. We kunnen hoogstens zeggen dat er twee verschillende concentraties van punten zijn in de Spending Score vs Age spreidingsdiagram.

Beide scatterplots bestaande uit Annual Income en Spending Score zijn in wezen hetzelfde. We kunnen het twee keer zien omdat de x- en y-as zijn verwisseld. Door een van hen te bekijken, kunnen we zien wat vijf verschillende groepen lijken te zijn. Laten we alleen die twee functies plotten met een Seaborn scatterplot() nader bekijken:

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

img

Door beter te kijken, kunnen we zeker 5 verschillende groepen gegevens onderscheiden. Het lijkt erop dat onze klanten kunnen worden geclusterd op basis van hoeveel ze in een jaar verdienen en hoeveel ze uitgeven. Dit is een ander relevant punt in onze analyse. Het is belangrijk dat we slechts twee functies in overweging nemen om onze klanten te groeperen. Alle andere informatie die we over hen hebben, komt niet in de vergelijking. Dit geeft de analyse betekenis - als we weten hoeveel een klant verdient en uitgeeft, kunnen we gemakkelijk de overeenkomsten vinden die we nodig hebben.

img

Dat is geweldig! Tot nu toe hebben we al twee variabelen om ons model te bouwen. Naast wat dit vertegenwoordigt, maakt het het model ook eenvoudiger, spaarzaam en beter verklaarbaar.

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

Opmerking: Data Science geeft meestal de voorkeur aan zo eenvoudig mogelijke benaderingen. Niet alleen omdat het voor de business makkelijker uit te leggen is, maar ook omdat het directer is – met 2 features en een verklaarbaar model is het duidelijk wat het model doet en hoe het werkt.

Gegevens plotten na gebruik van PCA

Het lijkt erop dat onze tweede benadering waarschijnlijk de beste is, maar laten we ook eens kijken naar onze derde benadering. Het kan handig zijn wanneer we de gegevens niet kunnen plotten omdat ze te veel dimensies hebben, of wanneer er geen gegevensconcentraties of duidelijke scheiding in groepen zijn. Wanneer deze situaties zich voordoen, is het raadzaam om de gegevensdimensies te verkleinen met een methode met de naam Hoofdcomponentenanalyse (PCA).

Opmerking: De meeste mensen gebruiken PCA voor dimensionaliteitsreductie vóór visualisatie. Er zijn andere methoden die helpen bij datavisualisatie voorafgaand aan clustering, zoals: Op dichtheid gebaseerde ruimtelijke clustering van toepassingen met ruis (DBSCAN) en Zelforganiserende kaarten (SOM) clusteren. Beide zijn clustering-algoritmen, maar kunnen ook worden gebruikt voor datavisualisatie. Aangezien clusteranalyse geen gouden standaard heeft, is het belangrijk om verschillende visualisaties en verschillende algoritmen te vergelijken.

PCA zal de afmetingen van onze gegevens verkleinen en tegelijkertijd proberen zoveel mogelijk van de informatie te behouden. Laten we eerst een idee krijgen van hoe PCA werkt, en dan kunnen we kiezen tot hoeveel gegevensdimensies we onze gegevens willen reduceren.

Voor elk paar kenmerken kijkt PCA of de grotere waarden van de ene variabele overeenkomen met de grotere waarden van de andere variabele, en doet hetzelfde voor de kleinere waarden. Het berekent dus in wezen hoeveel de kenmerkwaarden ten opzichte van elkaar verschillen - we noemen dat hun covariantie. Die resultaten worden vervolgens georganiseerd in een matrix, waardoor een covariantiematrix.

Nadat de covariantiematrix is ​​verkregen, probeert PCA een lineaire combinatie van kenmerken te vinden die deze het beste verklaart - het past lineaire modellen toe totdat het degene identificeert die de maximaal hoeveelheid variantie.

Note: PCA is een lineaire transformatie en lineariteit is gevoelig voor de schaal van gegevens. Daarom werkt PCA het beste wanneer alle gegevenswaarden zich op dezelfde schaal bevinden. Dit kan gedaan worden door de kolom af te trekken gemiddelde van zijn waarden en het resultaat te delen door zijn standaarddeviatie. Dat is genoemd gegevensstandaardisatie. Zorg ervoor dat de gegevens zijn geschaald voordat u PCA gebruikt! Als je niet zeker weet hoe, lees dan onze "Functieschaalgegevens met Scikit-Learn voor machine learning in Python"!

Met de beste gevonden lijn (lineaire combinatie), krijgt PCA de richtingen van zijn assen, genaamd eigenvectoren, en de lineaire coëfficiënten, de eigenwaarden. De combinatie van de eigenvectoren en eigenwaarden – of asrichtingen en coëfficiënten – zijn de Hoofdcomponenten van PCA. En dat is wanneer we ons aantal dimensies kunnen kiezen op basis van de verklaarde variantie van elk kenmerk, door te begrijpen welke hoofdcomponenten we willen behouden of weggooien op basis van hoeveel variantie ze verklaren.

Na het verkrijgen van de hoofdcomponenten, gebruikt PCA de eigenvectoren om een ​​vector van kenmerken te vormen die de gegevens heroriënteren van de oorspronkelijke assen naar die weergegeven door de hoofdcomponenten - zo worden de gegevensdimensies verkleind.

Opmerking: Een belangrijk detail om hier rekening mee te houden, is dat PCA, vanwege zijn lineaire karakter, de meeste verklaarde variantie zal concentreren in de eerste hoofdcomponenten. Dus als we naar de verklaarde variantie kijken, zijn meestal onze eerste twee componenten voldoende. Maar dat kan in sommige gevallen misleidend zijn - dus probeer verschillende plots en algoritmen te blijven vergelijken bij het clusteren om te zien of ze vergelijkbare resultaten opleveren.

Voordat we PCA toepassen, moeten we kiezen tussen de Age kolom of de Age Groups kolommen in onze voorheen one-hot gecodeerde gegevens. Aangezien beide kolommen dezelfde informatie vertegenwoordigen, heeft het twee keer introduceren ervan invloed op onze gegevensvariantie. Als de Age Groups kolom is gekozen, verwijdert u eenvoudig de Age kolom met behulp van de Panda's drop() methode en wijs deze opnieuw toe aan de customer_data_oh variabele:

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

Nu hebben onze gegevens 10 kolommen, wat betekent dat we één hoofdcomponent per kolom kunnen verkrijgen en kunnen kiezen hoeveel we zullen gebruiken door te meten hoeveel het introduceren van één nieuwe dimensie meer van onze gegevensvariantie verklaart.

Laten we dat doen met Scikit-Learn PCA. We zullen de verklaarde variantie van elke dimensie berekenen, gegeven door explained_variance_ratio_ , en kijk dan naar hun cumulatieve som met cumsum() :

from sklearn.decomposition import PCA

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

Onze cumulatief verklaarde varianties zijn:

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

We kunnen zien dat de eerste dimensie 50% van de gegevens verklaart, en wanneer ze worden gecombineerd met de tweede dimensie, verklaren ze 99% procent. Dit betekent dat de eerste 2 dimensies al 99% van onze data verklaren. We kunnen dus een PCA met 2 componenten toepassen, onze belangrijkste componenten verkrijgen en deze plotten:

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

De gegevensplot na PCA lijkt erg op de plot die slechts twee kolommen van de gegevens zonder PCA gebruikt. Merk op dat de punten die groepen vormen dichter bij elkaar liggen en iets meer geconcentreerd zijn na de PCA dan ervoor.

img

Hiërarchische structuur visualiseren met dendrogrammen

Tot nu toe hebben we de gegevens onderzocht, één-hot gecodeerde categorische kolommen, besloten welke kolommen geschikt waren voor clustering en de gegevensdimensionaliteit verminderd. De grafieken geven aan dat we 5 clusters in onze gegevens hebben, maar er is ook een andere manier om de relaties tussen onze punten te visualiseren en het aantal clusters te helpen bepalen - door een dendrogram (vaak verkeerd gespeld als dendogram). dendro middel boom in Latijns.

De dendrogram is een resultaat van het koppelen van punten in een dataset. Het is een visuele weergave van het hiërarchische clusteringproces. En hoe werkt het hiërarchische clusteringproces? Nou ... het hangt ervan af - waarschijnlijk een antwoord dat je al veel hebt gehoord in Data Science.

Hiërarchische clustering begrijpen

Wanneer de Hiërarchisch clustering algoritme (HCA) begint de punten te koppelen en clusters te vinden, kan het eerst punten in 2 grote groepen splitsen en vervolgens elk van die twee groepen in kleinere 2 groepen splitsen, met in totaal 4 groepen, wat de verdeeldheid en top-down nadering.

Als alternatief kan het het tegenovergestelde doen - het kan naar alle gegevenspunten kijken, 2 punten vinden die dichter bij elkaar liggen, deze koppelen en dan andere punten vinden die het dichtst bij die gekoppelde punten liggen en de 2 groepen blijven bouwen van de onderkant boven. Welke is de agglomeratie aanpak die we gaan ontwikkelen.

Stappen om agglomeratieve hiërarchische clustering uit te voeren

Om de agglomeratiebenadering nog duidelijk te maken, zijn er stappen van de Agglomeratieve hiërarchische clustering (AHC) algoritme:

  1. Behandel in het begin elk gegevenspunt als één cluster. Daarom is het aantal clusters aan het begin K - terwijl K een geheel getal is dat het aantal gegevenspunten vertegenwoordigt.
  2. Vorm een ​​cluster door de twee dichtstbijzijnde gegevenspunten samen te voegen, wat resulteert in K-1-clusters.
  3. Vorm meer clusters door de twee dichtstbijzijnde clusters samen te voegen, wat resulteert in K-2-clusters.
  4. Herhaal de bovenstaande drie stappen totdat één grote cluster is gevormd.

Note: Ter vereenvoudiging zeggen we in stap 2 en 3 "twee dichtstbijzijnde" gegevenspunten. Maar er zijn meer manieren om punten te koppelen, zoals we straks zullen zien.

Als je de stappen van het ACH-algoritme omkeert, van 4 naar 1, dan zijn dat de stappen naar *Verdeeldheid zaaiende hiërarchische clustering (DHC)*.

Merk op dat HCA's verdeeldheid kunnen zaaien en top-down, of agglomeratief en bottom-up. De top-down DHC-benadering werkt het beste als je minder, maar grotere clusters hebt, en is daarom rekenkundig duurder. Aan de andere kant is de bottom-up AHC-benadering geschikt voor als je veel kleinere clusters hebt. Het is rekenkundig eenvoudiger, meer gebruikt en meer beschikbaar.

Opmerking: Ofwel top-down of bottom-up, de dendrogram-representatie van het clusteringproces zal altijd beginnen met een deling in twee en eindigen met elk afzonderlijk punt gediscrimineerd, zodra de onderliggende structuur van een binaire boom is.

Laten we ons klantgegevensdendrogram plotten om de hiërarchische relaties van de gegevens te visualiseren. Deze keer gebruiken we de scipy bibliotheek om het dendrogram voor onze dataset te maken:

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

De uitvoer van het script ziet er als volgt uit:

img

In het bovenstaande script hebben we de clusters en subclusters gegenereerd met onze punten, gedefinieerd hoe onze punten zouden linken (door de toepassing van de ward methode), en hoe de afstand tussen punten te meten (met behulp van de euclidean metriek).

Met de plot van het dendrogram kunnen de beschreven processen van DHC en AHC worden gevisualiseerd. Om de top-downbenadering te visualiseren, begint u vanaf de bovenkant van het dendrogram en gaat u naar beneden, en doet u het tegenovergestelde, begint u naar beneden en gaat u omhoog om de bottom-upbenadering te visualiseren.

Koppelingsmethoden

Er zijn veel andere koppelingsmethoden, door meer te begrijpen over hoe ze werken, kunt u de juiste kiezen voor uw behoeften. Daarnaast zal elk van hen verschillende resultaten opleveren wanneer ze worden toegepast. Er is geen vaste regel in clusteranalyse, bestudeer indien mogelijk de aard van het probleem om te zien welke het beste past, test verschillende methoden en inspecteer de resultaten.

Enkele van de koppelingsmethoden zijn:

  • Enkele koppeling: ook wel aangeduid als Dichtstbijzijnde buur (NN). De afstand tussen clusters wordt bepaald door de afstand tussen hun dichtstbijzijnde leden.

img

  • Volledige koppeling: ook wel aangeduid als Verste Buur (FN), Algoritme van het verste puntof Voor Hees Algoritme. De afstand tussen clusters wordt bepaald door de afstand tussen hun verste leden. Deze methode is rekenkundig duur.

img

  • Gemiddelde koppeling: ook gekend als UPGMA (Ongewogen paargroepsmethode met rekenkundig gemiddelde). Het percentage van het aantal punten van elk cluster wordt berekend ten opzichte van het aantal punten van de twee clusters als ze waren samengevoegd.

img

  • Gewogen koppeling: ook gekend als WPGMA (Weighted Pair Group Method met rekenkundig gemiddelde). De individuele punten van de twee clusters dragen bij aan de geaggregeerde afstand tussen een kleiner en een groter cluster.
  • zwaartepunt koppeling: ook wel aangeduid als UPGMC (Ongewogen Pair Group-methode met behulp van Centroids). Een punt gedefinieerd door het gemiddelde van alle punten (zwaartepunt) wordt berekend voor elk cluster en de afstand tussen clusters is de afstand tussen hun respectieve zwaartepunten.

img

  • Afdelingskoppeling: Ook gekend als MISSQ (Minimale toename van Sum-of-Squares). Het specificeert de afstand tussen twee clusters, berekent de som van de kwadratenfout (ESS) en kiest achtereenvolgens de volgende clusters op basis van de kleinere ESS. De methode van Ward probeert de toename van ESS bij elke stap te minimaliseren. Fouten minimaliseren dus.

img

Afstandsstatistieken

Naast de koppeling kunnen we ook enkele van de meest gebruikte afstandsmetrieken specificeren:

  • Euclidische: ook wel aangeduid als Pythagoras of rechte lijn afstand. Het berekent de afstand tussen twee punten in de ruimte door de lengte te meten van een lijnstuk dat ertussen loopt. Het gebruikt de stelling van Pythagoras en de afstandswaarde is het resultaat (C) van de vergelijking:

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

  • Manhattan: ook wel genoemd Stadsblok, Taxi afstand. Het is de som van absolute verschillen tussen de maten in alle dimensies van twee punten. Als die afmetingen twee zijn, is het analoog aan het maken van een rechter- en vervolgens linksaf wanneer u een blok loopt.

img

  • Minkowski: het is een veralgemening van zowel Euclidische als Manhattan-afstanden. Het is een manier om afstanden te berekenen op basis van de absolute verschillen met de volgorde van de Minkowski-metriek p. Hoewel het is gedefinieerd voor elke p> 0, wordt het zelden gebruikt voor andere waarden dan 1, 2 en ∞ (oneindig). Minkowski-afstand is hetzelfde als Manhattan-afstand wanneer: p = 1, en hetzelfde als Euclidische afstand wanneer p = 2.

$$
Dlinks(X,Yrechts) = links(som_{i=1}^n |x_i-y_i|^prechts)^{frac{1}{p}}
$$

img

  • Chebyshev: ook gekend als Schaakbord afstand. Het is het extreme geval van Minkowski-afstand. Wanneer we oneindig gebruiken als de waarde van de parameter p (p = ), eindigen we met een metriek die afstand definieert als het maximale absolute verschil tussen coördinaten.
  • Cosinus: het is de hoekcosinusafstand tussen twee reeksen punten of vectoren. De cosinusovereenkomst is het puntproduct van de vectoren gedeeld door het product van hun lengtes.
  • Jaccard: meet de overeenkomst tussen eindige verzamelingen punten. Het wordt gedefinieerd als het totale aantal punten (kardinaliteit) in de gemeenschappelijke punten in elke reeks (kruising), gedeeld door het totale aantal punten (kardinaliteit) van het totaal aantal punten van beide reeksen (unie).
  • Jensen Shannon: gebaseerd op de Kullback-Leibler divergentie. Het houdt rekening met de kansverdelingen van de punten en meet de overeenkomst tussen die verdelingen. Het is een populaire methode van kansrekening en statistiek.

Wij hebben gekozen Afdeling en Euclidische voor het dendrogram omdat ze de meest gebruikte methode en metriek zijn. Ze geven meestal goede resultaten omdat Ward punten koppelt op basis van het minimaliseren van de fouten, en Euclidische werkt goed in lagere dimensies.

In dit voorbeeld werken we met twee features (kolommen) van de marketingdata en 200 observaties of rijen. Aangezien het aantal waarnemingen groter is dan het aantal kenmerken (200 > 2), werken we in een laagdimensionale ruimte.

Wanneer het aantal functies (F) groter is dan het aantal waarnemingen (N) - meestal geschreven als f >> Nee, het betekent dat we een hoge dimensionale ruimte.

Als we meer attributen zouden opnemen, dus we hebben meer dan 200 kenmerken, zou de Euclidische afstand misschien niet zo goed werken, omdat het moeilijk zou zijn om alle kleine afstanden te meten in een zeer grote ruimte die alleen maar groter wordt. Met andere woorden, de Euclidische afstandsbenadering heeft moeite met het werken met de gegevens schaarsheid. Dit is een probleem dat wordt genoemd de vloek van de dimensionaliteit. De afstandswaarden zouden zo klein worden, alsof ze "verdund" werden in de grotere ruimte, vervormd totdat ze 0 werden.

Opmerking: Als u ooit een dataset tegenkomt met: f >> p, zult u waarschijnlijk andere afstandsstatistieken gebruiken, zoals de Mahalanobis afstand. Als alternatief kunt u ook de afmetingen van de dataset verkleinen door gebruik te maken van Hoofdcomponentenanalyse (PCA). Dit probleem komt vaak voor, vooral bij het clusteren van biologische sequentiegegevens.

We hebben het al gehad over statistieken, koppelingen en hoe elk daarvan onze resultaten kan beïnvloeden. Laten we nu doorgaan met de dendrogram-analyse en kijken hoe het ons een indicatie kan geven van het aantal clusters in onze dataset.

Het vinden van een interessant aantal clusters in een dendrogram is hetzelfde als het vinden van de grootste horizontale ruimte zonder verticale lijnen (de ruimte met de langste verticale lijnen). Dit betekent dat er meer scheiding is tussen de clusters.

We kunnen een horizontale lijn tekenen die door die langste afstand gaat:

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

Nadat we de horizontale lijn hebben gevonden, tellen we hoe vaak onze verticale lijnen erdoor zijn gekruist - in dit voorbeeld 5 keer. Dus 5 lijkt een goede indicatie van het aantal clusters met de meeste afstand ertussen.

Note: Het dendrogram moet alleen als referentie worden beschouwd wanneer het wordt gebruikt om het aantal clusters te kiezen. Het kan dat aantal gemakkelijk wegkrijgen en wordt volledig beïnvloed door het type koppeling en afstandsstatistieken. Bij het uitvoeren van een diepgaande clusteranalyse is het raadzaam om te kijken naar dendrogrammen met verschillende koppelingen en metrieken en om te kijken naar de resultaten die worden gegenereerd met de eerste drie regels waarin de clusters de meeste afstand tussen de clusters hebben.

Een agglomeratieve hiërarchische clustering implementeren

Originele gegevens gebruiken

Tot nu toe hebben we het voorgestelde aantal clusters voor onze dataset berekend dat overeenkomt met onze initiële analyse en onze PCA-analyse. Nu kunnen we ons agglomeratieve hiërarchische clustermodel maken met behulp van Scikit-Learn AgglomerativeClustering en ontdek de labels van marketingpunten met labels_:

from sklearn.cluster import AgglomerativeClustering

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

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

We hebben veel onderzocht om tot dit punt te komen. En wat betekenen deze labels? Hier hebben we elk punt van onze gegevens gelabeld als een groep van 0 tot 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

Dit zijn onze laatste geclusterde gegevens. U kunt de kleurgecodeerde gegevenspunten zien in de vorm van vijf clusters.

De datapunten rechtsonder (label: 0, paarse datapunten) behoren tot de klanten met hoge salarissen maar lage uitgaven. Dit zijn de klanten die hun geld zorgvuldig besteden.

Zo ook de klanten rechtsboven (label: 2, groene datapunten), zijn de klanten met hoge salarissen en hoge uitgaven. Dit zijn het soort klanten waarop bedrijven zich richten.

De klanten in het midden (label: 1, blauwe gegevenspunten) zijn degenen met een gemiddeld inkomen en gemiddelde uitgaven. De hoogste aantallen klanten behoren tot deze categorie. Bedrijven kunnen zich ook op deze klanten richten, gezien het feit dat ze in grote aantallen zijn.

De klanten linksonder (label: 4, rood) zijn de klanten met lage salarissen en lage uitgaven, ze kunnen worden aangetrokken door promoties aan te bieden.

En tot slot de klanten linksboven (label: 3, oranje datapunten) zijn degenen met een hoog inkomen en lage uitgaven, die bij uitstek het doelwit zijn van marketing.

Het resultaat van PCA gebruiken

Als we ons in een ander scenario bevonden, waarin we de dimensionaliteit van data moesten verminderen. We zouden ook gemakkelijk de geclusterde PCA-resultaten kunnen plotten. Dat kan door een ander agglomeratief clustermodel te maken en voor elke hoofdcomponent een gegevenslabel te verkrijgen:

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

Merk op dat beide resultaten erg op elkaar lijken. Het belangrijkste verschil is dat het eerste resultaat met de originele gegevens veel gemakkelijker te verklaren is. Duidelijk is te zien dat klanten op basis van hun jaarlijkse inkomens- en bestedingsscore in vijf groepen kunnen worden ingedeeld. Hoewel we bij de PCA-aanpak al onze functies in overweging nemen, voor zover we kunnen kijken naar de variantie die door elk van hen wordt verklaard, is dit een moeilijker concept om te begrijpen, vooral wanneer we rapporteren aan een marketingafdeling.

Hoe minder we onze gegevens hoeven te transformeren, hoe beter.

Als u een zeer grote en complexe dataset heeft waarin u vóór clustering een dimensionaliteitsreductie moet uitvoeren, probeer dan de lineaire relaties tussen elk van de kenmerken en hun residuen te analyseren om het gebruik van PCA te ondersteunen en de verklaarbaarheid van het proces te verbeteren. Door een lineair model per paar kenmerken te maken, kunt u begrijpen hoe de kenmerken op elkaar inwerken.

Als het gegevensvolume zo groot is, wordt het onmogelijk om de paren kenmerken te plotten, een steekproef van uw gegevens te selecteren, zo evenwichtig en zo dicht mogelijk bij de normale verdeling mogelijk en eerst de analyse op de steekproef uit te voeren, het te begrijpen, af te stemmen het – en pas het later toe op de hele dataset.

U kunt altijd verschillende visualisatietechnieken voor clustering kiezen, afhankelijk van de aard van uw gegevens (lineair, niet-lineair) en ze indien nodig allemaal combineren of testen.

Conclusie

De clustertechniek kan erg handig zijn als het gaat om ongelabelde data. Aangezien de meeste gegevens in de echte wereld niet-gelabeld zijn en het annoteren van de gegevens hogere kosten met zich meebrengt, kunnen clustertechnieken worden gebruikt om niet-gelabelde gegevens te labelen.

In deze gids hebben we een echt datawetenschapsprobleem naar voren gebracht, aangezien clusteringtechnieken grotendeels worden gebruikt in marketinganalyse (en ook in biologische analyse). We hebben ook veel van de onderzoeksstappen uitgelegd om tot een goed hiërarchisch clustermodel te komen en hoe dendrogrammen te lezen en ons af te vragen of PCA een noodzakelijke stap is. Ons belangrijkste doel is dat enkele van de valkuilen en verschillende scenario's waarin we hiërarchische clustering kunnen vinden, worden afgedekt.

Gelukkig clusteren!

Tijdstempel:

Meer van Stapelmisbruik