Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn

Wprowadzenie

Grupowanie K-oznacza jest jednym z najczęściej używanych nienadzorowanych algorytmów uczenia maszynowego, które tworzą klastry danych na podstawie podobieństwa między instancjami danych.

W tym przewodniku najpierw przyjrzymy się prostemu przykładowi, aby zrozumieć, jak działa algorytm K-Means przed wdrożeniem go za pomocą Scikit-Learn. Następnie omówimy, jak określić liczbę skupień (Ks) w K-średnich, a także omówimy metryki odległości, wariancję oraz K-średnie za i przeciw.

Motywacja

Wyobraź sobie następującą sytuację. Pewnego dnia, spacerując po okolicy, zauważyłeś 10 sklepów ogólnospożywczych i zacząłeś się zastanawiać, które sklepy są podobne – bliżej siebie. Szukając odpowiedzi na to pytanie, natknąłeś się na ciekawe podejście, które dzieli sklepy na grupy na podstawie ich współrzędnych na mapie.

Na przykład, jeśli jeden sklep znajduje się 5 km na zachód i 3 km na północ – przypiszesz (5, 3) współrzędne do niego i przedstawić go na wykresie. Narysujmy ten pierwszy punkt, aby zwizualizować, co się dzieje:

import matplotlib.pyplot as plt

plt.title("Store With Coordinates (5, 3)")
plt.scatter(x=5, y=3)

To dopiero pierwszy punkt, więc możemy zorientować się, jak możemy reprezentować sklep. Powiedzmy, że mamy już 10 współrzędnych 10 zebranych sklepów. Po zorganizowaniu ich w numpy tablicy, możemy również wykreślić ich lokalizacje:

import numpy as np

points = np.array([[5, 3], [10, 15], [15, 12], [24, 10], [30, 45], [85, 70], [71, 80], [60, 78], [55, 52],[80, 91]])

xs = points[:,0] 
ys = points[:,1]  

plt.title("10 Stores Coordinates")
plt.scatter(x=xs, y=ys)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Jak ręcznie zaimplementować algorytm k-średnich

Teraz możemy spojrzeć na 10 sklepów na wykresie, a głównym problemem jest znalezienie sposobu, w jaki można je podzielić na różne grupy na podstawie bliskości? Wystarczy tylko rzucić okiem na wykres, prawdopodobnie zauważymy dwie grupy sklepów – jeden to dolne punkty w lewym dolnym rogu, a drugi to punkty w prawym górnym rogu. Być może możemy nawet rozróżnić te dwa punkty w środku jako odrębną grupę – a więc tworząc trzy różne grupy.

W tej sekcji omówimy proces ręcznego grupowania punktów – dzielenia ich na określoną liczbę grup. W ten sposób zasadniczo dokładnie omówimy wszystkie etapy Algorytm grupowania K-średnich. Pod koniec tej sekcji zdobędziesz zarówno intuicyjne, jak i praktyczne zrozumienie wszystkich kroków wykonywanych podczas grupowania K-średnich. Następnie przekażemy to do Scikit-Learn.

Jaki byłby najlepszy sposób określenia, czy istnieją dwie lub trzy grupy punktów? Jednym prostym sposobem byłoby po prostu wybranie jednej liczby grup – na przykład dwóch – a następnie próba grupowania punktów na podstawie tego wyboru.

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Powiedzmy, że zdecydowaliśmy, że są dwie grupy naszych sklepów (punkty). Teraz musimy znaleźć sposób na zrozumienie, które punkty należą do której grupy. Można to zrobić, wybierając jeden punkt do reprezentowania grupa 1 i jeden do reprezentowania grupa 2. Punkty te będą używane jako odniesienie podczas pomiaru odległości od wszystkich innych punktów do każdej grupy.

W ten sposób powiedz punkt (5, 3) kończy się przynależnością do grupy 1, a punkt (79, 60) do grupy 2. Próbując przypisać nowy punkt (6, 3) do grup, musimy zmierzyć jego odległość do tych dwóch punktów. W przypadku punktu (6, 3) is bliższy do (5, 3), dlatego należy do grupy reprezentowanej przez ten punkt – grupa 1. W ten sposób możemy łatwo pogrupować wszystkie punkty w odpowiednie grupy.

W tym przykładzie oprócz określenia liczby grup (klastry) – również wybieramy kilka punktów, które mają być odniesienie odległości dla nowych punktów każdej grupy.

To jest ogólna idea, aby zrozumieć podobieństwa między naszymi sklepami. Przełóżmy to na praktykę – najpierw możemy wybrać dwa punkty odniesienia w przypadkowy. Punkt odniesienia grupa 1 będzie (5, 3) i punkt odniesienia grupa 2 będzie (10, 15). Możemy wybrać oba punkty naszego numpy tablica według [0] i [1] indeksów i przechowuj je w g1 (grupa 1) i g2 (grupa 2) zmienne:

g1 = points[0]
g2 = points[1]

Po wykonaniu tej czynności musimy obliczyć odległość od wszystkich innych punktów do tych punktów odniesienia. Rodzi to ważne pytanie – jak zmierzyć tę odległość. Zasadniczo możemy użyć dowolnej miary odległości, ale na potrzeby tego przewodnika użyjmy Odległość euklidesową_.

Warto wiedzieć, że miara odległości euklidesowej jest oparta na twierdzeniu Pitagorasa:

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

Przy dostosowaniu do punktów na płaszczyźnie – (a1, b1) i (a2, b2), poprzednia formuła staje się:

$$
c^2 = (a2-a1)^2 + (b2-b1)^2
$$

Odległość będzie pierwiastkiem kwadratowym z c, więc możemy również zapisać formułę jako:

$$
euklidesowa_{odleg} = sqrt[2][(a2 – a1)^2 + (b2 – b1) ^2)]
$$

Uwaga: Możesz także uogólnić wzór odległości euklidesowej dla punktów wielowymiarowych. Na przykład w przestrzeni trójwymiarowej punkty mają trzy współrzędne – nasz wzór odzwierciedla to w następujący sposób:
$$
euklides_{odst} = sqrt[2][(a2 – a1)^2 + (b2 – b1) ^2 + (c2 – c1) ^2)]
$$
Ta sama zasada obowiązuje bez względu na ilość wymiarów przestrzeni, w której działamy.

Do tej pory wybraliśmy punkty reprezentujące grupy i wiemy, jak obliczać odległości. Teraz połączmy odległości i grupy, przypisując każdy z naszych zebranych punktów sklepowych do grupy.

Aby lepiej to zobrazować, zadeklarujemy trzy listy. Pierwszy do przechowywania punktów z pierwszej grupy – points_in_g1. Drugi do przechowywania punktów z grupy 2 – points_in_g2, i ostatni - group, do etykieta punkty jako albo 1 (należy do grupy 1) lub 2 (należy do grupy 2):

points_in_g1 = []
points_in_g2 = []
group = []

Możemy teraz iterować przez nasze punkty i obliczyć odległość euklidesową między nimi a każdym z naszych odniesień grupowych. Każdy punkt będzie bliższy do jednej z dwóch grup – w zależności od tego, która grupa jest najbliżej, przypiszemy każdy punkt do odpowiedniej listy, jednocześnie dodając 1 or 2 do group lista:

for p in points:
    x1, y1 = p[0], p[1]
    euclidean_distance_g1 = np.sqrt((g1[0] - x1)**2 + (g1[1] - y1)**2)
    euclidean_distance_g2 = np.sqrt((g2[0] - x1)**2 + (g2[1] - y1)**2)
    if euclidean_distance_g1 < euclidean_distance_g2:
        points_in_g1.append(p)
        group.append('1')
    else:
        points_in_g2.append(p)
        group.append('2')

Spójrzmy na wyniki tej iteracji, aby zobaczyć, co się stało:

print(f'points_in_g1:{points_in_g1}n 
npoints_in_g2:{points_in_g2}n 
ngroup:{group}')

Co skutkuje w:

points_in_g1:[array([5, 3])]
 
points_in_g2:[array([10, 15]), array([15, 12]), 
              array([24, 10]), array([30, 45]), 
              array([85, 70]), array([71, 80]),
              array([60, 78]), array([55, 52]), 
              array([80, 91])]
 
group:[1, 2, 2, 2, 2, 2, 2, 2, 2, 2] 

Możemy również wykreślić wynik grupowania, z różnymi kolorami w oparciu o przypisane grupy, używając Seaborn's scatterplot() z group jak hue Argument:

import seaborn as sns

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Widać wyraźnie, że tylko nasz pierwszy punkt jest przypisany do grupy 1, a wszystkie pozostałe do grupy 2. Ten wynik różni się od tego, co wyobrażaliśmy sobie na początku. Biorąc pod uwagę różnicę między naszymi wynikami a naszymi początkowymi oczekiwaniami – czy możemy to zmienić? Wygląda na to, że jest!

Jednym z podejść jest powtórzenie procesu i wybranie różnych punktów, które będą punktami odniesienia dla grup. Miejmy nadzieję, że to zmieni nasze wyniki, bardziej zgodne z tym, co planowaliśmy na początku. Za drugim razem mogliśmy wybrać je nie losowo, jak wcześniej, ale uzyskując oznaczać wszystkich naszych już zgrupowanych punktów. W ten sposób te nowe punkty można by umieścić w środku odpowiednich grup.

Na przykład, jeśli druga grupa miała tylko punkty (10, 15), (30, 45). Nowy centralny punkt byłby (10 + 30)/2 i (15+45)/2 – co jest równe (20, 30).

Ponieważ umieściliśmy nasze wyniki w listach, możemy je najpierw przekonwertować na numpy tablice, wybierz ich xs, ys, a następnie uzyskaj oznaczać:

g1_center = [np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()]
g2_center = [np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()]
g1_center, g2_center

Rada: Spróbuj użyć numpy i NumPy jak najwięcej. Są zoptymalizowane pod kątem lepszej wydajności i upraszczają wiele operacji algebry liniowej. Ilekroć próbujesz rozwiązać jakiś problem z algebry liniowej, zdecydowanie powinieneś spojrzeć na numpy dokumentacja, aby sprawdzić, czy istnieje numpy metoda zaprojektowana, aby rozwiązać Twój problem. Szansa jest taka, że ​​jest!

Aby pomóc powtórzyć proces z naszymi nowymi punktami środkowymi, przekształćmy nasz poprzedni kod w funkcję, wykonaj ją i zobaczmy, czy nastąpiły jakieś zmiany w sposobie grupowania punktów:

def assigns_points_to_two_groups(g1_center, g2_center):
    points_in_g1 = []
    points_in_g2 = []
    group = []

    for p in points:
        x1, y1 = p[0], p[1]
        euclidean_distance_g1 = np.sqrt((g1_center[0] - x1)**2 + (g1_center[1] - y1)**2)
        euclidean_distance_g2 = np.sqrt((g2_center[0] - x1)**2 + (g2_center[1] - y1)**2)
        if euclidean_distance_g1 < euclidean_distance_g2:
            points_in_g1.append(p)
            group.append(1)
        else:
            points_in_g2.append(p)
            group.append(2)
    return points_in_g1, points_in_g2, group

Uwaga: Jeśli zauważysz, że ciągle powtarzasz ten sam kod, powinieneś umieścić ten kod w osobnej funkcji. Uważa się, że najlepszą praktyką jest organizowanie kodu w funkcje, szczególnie dlatego, że ułatwiają one testowanie. Łatwiej jest przetestować i wyizolować fragment kodu niż pełny kod bez żadnych funkcji.

Wywołajmy funkcję i zapiszmy jej wyniki w points_in_g1, points_in_g2, group zmienne:

points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
points_in_g1, points_in_g2, group

A także narysuj wykres rozrzutu z kolorowymi punktami, aby zwizualizować podział grup:

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Wygląda na to, że skupienie naszych punktów jest poprawia się. Mimo to na środku wykresu znajdują się dwa punkty, które można przypisać do dowolnej grupy, biorąc pod uwagę ich bliskość do obu grup. Opracowany do tej pory algorytm przypisuje oba te punkty do drugiej grupy.

Oznacza to, że prawdopodobnie możemy powtórzyć ten proces jeszcze raz, wykorzystując środki X i Y, tworząc dwa nowe punkty centralne (centroidy) do naszych grup i ponowne przydzielanie ich na podstawie odległości.

Stwórzmy również funkcję do aktualizacji centroidów. Cały proces można teraz sprowadzić do wielu wywołań tej funkcji:

def updates_centroids(points_in_g1, points_in_g2):
    g1_center = np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()
    g2_center = np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()
    return g1_center, g2_center

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Zauważ, że po tej trzeciej iteracji każdy z punktów należy teraz do różnych klastrów. Wygląda na to, że wyniki są coraz lepsze – zróbmy to jeszcze raz. Teraz idzie do czwarta iteracja naszej metody:

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Ten czwarty raz dostaliśmy ten sam wynik jak poprzedni. Wygląda więc na to, że nasze punkty nie zmienią już grup, nasz wynik osiągnął pewien rodzaj stabilności – osiągnął stan niezmienny lub konwergentnych. Poza tym mamy dokładnie taki sam wynik, jaki przewidywaliśmy dla dwóch grup. Widzimy też, czy ten osiągnięty podział ma sens.

Przypomnijmy szybko, co zrobiliśmy do tej pory. Podzieliliśmy nasze 10 sklepów geograficznie na dwie sekcje – jedną w dolnych regionach południowo-zachodnich, a drugą na północnym wschodzie. Interesujące może być zebranie większej ilości danych poza tym, co już mamy – przychody, dzienna liczba klientów i wiele innych. W ten sposób możemy przeprowadzić bogatszą analizę i być może wygenerować ciekawsze wyniki.

Takie badania klastrowe można przeprowadzić, gdy już ugruntowana marka chce wybrać obszar do otwarcia nowego sklepu. W takim przypadku oprócz lokalizacji branych jest pod uwagę znacznie więcej zmiennych.

Co to wszystko ma wspólnego z algorytmem K-średnich?

Postępując zgodnie z tymi krokami, być może zastanawiałeś się, co mają one wspólnego z algorytmem K-średnich. Proces, który przeprowadziliśmy do tej pory, to Algorytm K-średnich. Krótko mówiąc, określiliśmy liczbę grup/klastrów, losowo wybraliśmy początkowe punkty i zaktualizowaliśmy centroidy w każdej iteracji, aż do zbieżności klastrów. Cały algorytm wykonaliśmy w zasadzie ręcznie – starannie przeprowadzając każdy krok.

Połączenia K w K-Means pochodzi z liczba klastrów które należy ustawić przed rozpoczęciem procesu iteracji. W naszym przypadku K = 2. Ta cecha jest czasami postrzegana jako ujemny biorąc pod uwagę, że istnieją inne metody grupowania, takie jak klastrowanie hierarchiczne, które nie muszą mieć wcześniej ustalonej liczby klastrów.

Ze względu na użycie środków, K-środki również stają się wrażliwy na wartości odstające i ekstremalne – zwiększają zmienność i utrudniają naszym centroidom odgrywanie swojej roli. Bądź więc świadomy potrzeby wykonywania wartości ekstremalne i analiza wartości odstających przed przeprowadzeniem klastrowania przy użyciu algorytmu K-Means.

Zauważ również, że nasze punkty zostały podzielone na części proste, nie ma krzywych podczas tworzenia klastrów. Może to być również wadą algorytmu K-średnich.

Uwaga: Jeśli chcesz, aby była bardziej elastyczna i dostosowywała się do elips i innych kształtów, spróbuj użyć a uogólniony model K-średnich mieszaniny Gaussa. Model ten można dostosować do eliptycznych klastrów segmentacji.

K-Means ma również wiele Zalety! Działa dobrze na dużych zbiorów danych co może być trudne w obsłudze, jeśli używasz niektórych typów hierarchicznych algorytmów grupowania. To również gwarantuje konwergencjęi może łatwo generalizować i przystosować. Poza tym jest to prawdopodobnie najczęściej używany algorytm grupowania.

Teraz, gdy przejrzeliśmy wszystkie kroki wykonywane w algorytmie K-Means i zrozumieliśmy wszystkie jego zalety i wady, możemy wreszcie zaimplementować K-Means przy użyciu biblioteki Scikit-Learn.

Jak zaimplementować algorytm K-średnich za pomocą Nauka Scikit

Aby dokładnie sprawdzić nasz wynik, zróbmy ten proces jeszcze raz, ale teraz używając 3 wierszy kodu z sklearn:

from sklearn.cluster import KMeans


kmeans = KMeans(n_clusters=2, random_state=42) 
kmeans.fit(points)
kmeans.labels_

Tutaj etykiety są takie same, jak nasze poprzednie grupy. Po prostu szybko wykreślmy wynik:

sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Wynikowa działka jest taka sama jak ta z poprzedniej sekcji.

Zapoznaj się z naszym praktycznym, praktycznym przewodnikiem dotyczącym nauki Git, zawierającym najlepsze praktyki, standardy przyjęte w branży i dołączoną ściągawkę. Zatrzymaj polecenia Google Git, a właściwie uczyć się to!

Uwaga: Już samo spojrzenie na to, jak wykonaliśmy algorytm K-średnich za pomocą Scikit-Learn, może sprawić wrażenie, że jest to oczywiste i że nie musisz się tym zbytnio martwić. Tylko 3 wiersze kodu wykonują wszystkie kroki, które omówiliśmy w poprzedniej sekcji, gdy omówiliśmy krok po kroku algorytm K-średnich. Ale, diabeł tkwi w szczegółach w tym przypadku! Jeśli nie zrozumiesz wszystkich kroków i ograniczeń algorytmu, najprawdopodobniej spotkasz się z sytuacją, w której algorytm K-średnich daje wyniki, których nie oczekiwałeś.

Dzięki Scikit-Learn możesz również zainicjować K-Means dla szybszej konwergencji, ustawiając init='k-means++' argument. W szerszym ujęciu K-średnie++ nadal wybiera k początkowe skupienia skupiają się losowo według równomiernego rozkładu. Następnie każde kolejne centrum skupień jest wybierane z pozostałych punktów danych nie tylko przez obliczenie miary odległości, ale przez wykorzystanie prawdopodobieństwa. Korzystanie z prawdopodobieństwa przyspiesza działanie algorytmu i jest pomocne w przypadku bardzo dużych zbiorów danych.

Metoda łokcia – wybór najlepszej liczby grup

Na razie w porządku! Pogrupowaliśmy 10 sklepów na podstawie odległości euklidesowej między punktami a centroidami. Ale co z tymi dwoma punktami na środku wykresu, które są nieco trudniejsze do zgrupowania? Czy oni też nie mogliby stworzyć osobnej grupy? Czy rzeczywiście popełniliśmy błąd wybierając? K = 2 grupy? Może rzeczywiście mieliśmy K = 3 grupy? Moglibyśmy nawet mieć więcej niż trzy grupy i nie zdawać sobie z tego sprawy.

Zadawane tutaj pytanie brzmi: jak określić liczbę grup (K) w K-Means. Aby odpowiedzieć na to pytanie, musimy zrozumieć, czy istniałby „lepszy” klaster dla innej wartości K.

Naiwnym sposobem ustalenia tego jest grupowanie punktów o różnych wartościach K, więc dla K=2, K=3, K=4 i tak dalej:

for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 

Ale punkty grupowania dla różnych Ks sam nie wystarczy aby zrozumieć, czy wybraliśmy idealną wartość dla K. Potrzebujemy sposobu na ocenę jakości klastrowania dla każdego K wybraliśmy.

Ręczne obliczanie W ramach klastra Suma kwadratów (WCSS)

Oto idealne miejsce, aby wprowadzić miarę tego, jak bardzo nasze skupione punkty są blisko siebie. Zasadniczo opisuje, ile zmienność mamy wewnątrz jednego klastra. Ten środek nazywa się W ramach klastra Suma kwadratówlub WCSS w skrócie. Im mniejszy WCSS, tym bliżej są nasze punkty, dlatego mamy lepiej uformowany klaster. Formuła WCSS może być stosowana dla dowolnej liczby klastrów:

$$
WCSS = suma(Pi_1 – Centroid_1)^2 + cdots + suma(Pi_n – Centroid_n)^2
$$

Uwaga: W tym przewodniku używamy Odległość euklidesowa aby uzyskać centroidy, ale można również użyć innych miar odległości, takich jak Manhattan.

Teraz możemy założyć, że zdecydowaliśmy się mieć dwa klastry i spróbować zaimplementować WCSS, aby lepiej zrozumieć, czym jest WCSS i jak z niego korzystać. Jak wynika ze wzoru, musimy zsumować kwadraty różnic między wszystkimi punktami skupień i centroidami. Tak więc, jeśli nasz pierwszy punkt z pierwszej grupy to (5, 3) a nasz ostatni centroid (po zbieżności) z pierwszej grupy to (16.8, 17.0), WCSS będzie:

$$
WCSS = suma((5,3) – (16.8, 17.0))^2
$$

$$
WCSS = suma((5-16.8) + (3-17.0))^2
$$

$$
WCSS = suma((-11.8) + (-14.0))^2
$$

$$
WCSS = suma((-25.8))^2
$$

$$
WCSS = 335.24
$$

Ten przykład ilustruje, jak obliczamy WCSS dla jednego punktu z klastra. Jednak klaster zazwyczaj zawiera więcej niż jeden punkt i musimy wziąć je wszystkie pod uwagę podczas obliczania WCSS. Zrobimy to, definiując funkcję, która otrzymuje klaster punktów i centroidów i zwraca sumę kwadratów:

def sum_of_squares(cluster, centroid):
    squares = []
    for p in cluster:
        squares.append((p - centroid)**2)
        ss = np.array(squares).sum()
    return ss

Teraz możemy otrzymać sumę kwadratów dla każdego skupienia:

g1 = sum_of_squares(points_in_g1, g1_center)
g2 = sum_of_squares(points_in_g2, g2_center)

I zsumuj wyniki, aby uzyskać sumę WCSS:

g1 + g2

To skutkuje:

2964.3999999999996

Tak więc w naszym przypadku, kiedy K równa się 2, całkowity WCSS wynosi 2964.39. Teraz możemy zamienić Ks i obliczyć WCSS dla nich wszystkich. W ten sposób możemy uzyskać wgląd w to, co K powinniśmy wybrać, aby nasze klastrowanie działało jak najlepiej.

Obliczenie WCSS Korzystanie z Nauka Scikit

Na szczęście nie musimy ręcznie obliczać WCSS dla każdego K. Po wykonaniu klastrowania K-Means dla danej liczby klastrów, możemy uzyskać jego WCSS za pomocą funkcji inertia_ atrybut. Teraz możemy wrócić do naszych K-Means for pętli, użyj jej do zmiany liczby klastrów i wymień odpowiednie wartości WCSS:

wcss = [] 
for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 
    wcss.append(kmeans.inertia_)
wcss

Zauważ, że druga wartość na liście jest dokładnie taka sama, jaką obliczyliśmy wcześniej dla K = 2:

[18272.9, # For k=1 
 2964.3999999999996, # For k=2
 1198.75, # For k=3
 861.75,
 570.5,
 337.5,
 175.83333333333334,
 79.5,
 17.0,
 0.0]

Aby zwizualizować te wyniki, wykreślmy nasze Ks wraz z wartościami WCSS:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Następuje przerwa w fabule, gdy x = 2, niski punkt w linii, a jeszcze niższy, gdy x = 3. Zauważ, że przypomina nam to o kształt łokcia. Wykreślając Ks wraz z WCSS, używamy Metoda łokcia wybrać liczbę Ks. A wybrany K jest dokładnie najniższym punktem łokcia, więc byłoby 3 zamiast 2, w naszym przypadku:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss);
plt.axvline(3, linestyle='--', color='r')

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Możemy ponownie uruchomić algorytm klastrowy K-średnich, aby zobaczyć, jak nasze dane będą wyglądały z trzy klastry:

kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(points)
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Byliśmy już zadowoleni z dwóch klastrów, ale zgodnie z metodą łokcia trzy klastry lepiej pasowałyby do naszych danych. W tym przypadku mielibyśmy trzy rodzaje sklepów zamiast dwóch. Przed zastosowaniem metody łokcia myśleliśmy o skupiskach sklepów na południowym i północnym wschodzie, teraz mamy też sklepy w centrum. Może to byłaby dobra lokalizacja do otwarcia kolejnego sklepu, ponieważ w pobliżu byłoby mniej konkurencji.

Alternatywne Miary Jakości Klastra

Istnieją również inne miary, które można wykorzystać przy ocenie jakości klastra:

  • Wynik sylwetki – analizuje nie tylko odległość między punktami wewnątrz klastra, ale także między samymi klastrami
  • Między skupieniami Suma kwadratów (BCSS) – metryka komplementarna do WCSS
  • Błąd sumy kwadratów (SSE)
  • Maksymalny promień – mierzy największą odległość od punktu do jego środka ciężkości
  • Średni promień – suma największej odległości od punktu do jego środka ciężkości podzielona przez liczbę skupień.

Zaleca się eksperymentowanie i poznanie każdego z nich, ponieważ w zależności od problemu niektóre alternatywy mogą mieć większe zastosowanie niż najczęściej używane dane (WCSS i wynik sylwetki).

Ostatecznie, podobnie jak w przypadku wielu algorytmów analizy danych, chcemy zmniejszyć wariancję wewnątrz każdego klastra i zmaksymalizować wariancję między różnymi klastrami. Mamy więc więcej zdefiniowanych i dających się oddzielić klastrów.

Stosowanie K-średnich w innym zbiorze danych

Wykorzystajmy to, czego się nauczyliśmy na innym zbiorze danych. Tym razem postaramy się znaleźć grupy podobnych win.

Uwaga: Możesz pobrać zbiór danych tutaj.

Zaczynamy od importu pandas przeczytać wine-clustering CSV (Wartości rozdzielone przecinkami) plik do Dataframe struktura:

import pandas as pd

df = pd.read_csv('wine-clustering.csv')

Po załadowaniu rzućmy okiem na pierwsze pięć rekordów danych za pomocą head() metoda:

df.head()

To skutkuje:

	Alcohol 	Malic_Acid 	Ash 	Ash_Alcanity 	Magnesium 	Total_Phenols 	Flavanoids 	Nonflavanoid_Phenols 	Proanthocyanins 	Color_Intensity 	Hue 	OD280 	Proline
0 	14.23 		1.71 		2.43 	15.6 			127 		2.80 			3.06 		0.28 					2.29 				5.64 				1.04 	3.92 	1065
1 	13.20 		1.78 		2.14 	11.2 			100 		2.65 			2.76 		0.26 					1.28 				4.38 				1.05 	3.40 	1050
2 	13.16 		2.36 		2.67 	18.6 			101 		2.80 			3.24 		0.30 					2.81 				5.68 				1.03 	3.17 	1185
3 	14.37 		1.95 		2.50 	16.8 			113 		3.85 			3.49 		0.24 					2.18 				7.80 				0.86 	3.45 	1480
4 	13.24 		2.59 		2.87 	21.0 			118 		2.80 			2.69 		0.39 					1.82 				4.32 				1.04 	2.93 	735

Posiadamy wiele pomiarów substancji obecnych w winach. Tutaj również nie będziemy musieli przekształcać kolumn kategorialnych, ponieważ wszystkie są liczbowe. Przyjrzyjmy się teraz statystykom opisowym za pomocą describe() metoda:

df.describe().T 

Opis tabeli:

 						count 	mean 		std 		min 	25% 	50% 	75% 		max
Alcohol 				178.0 	13.000618 	0.811827 	11.03 	12.3625 13.050 	13.6775 	14.83
Malic_Acid 				178.0 	2.336348 	1.117146 	0.74 	1.6025 	1.865 	3.0825 		5.80
Ash 					178.0 	2.366517 	0.274344 	1.36 	2.2100 	2.360 	2.5575 		3.23
Ash_Alcanity 			178.0 	19.494944 	3.339564 	10.60 	17.2000 19.500 	21.5000 	30.00
Magnesium 				178.0 	99.741573 	14.282484 	70.00 	88.0000 98.000 	107.0000 	162.00
Total_Phenols 			178.0 	2.295112 	0.625851 	0.98 	1.7425 	2.355 	2.8000 		3.88
Flavanoids 				178.0 	2.029270 	0.998859 	0.34 	1.2050 	2.135 	2.8750 		5.08
Nonflavanoid_Phenols 	178.0 	0.361854 	0.124453 	0.13 	0.2700 	0.340 	0.4375 		0.66
Proanthocyanins 		178.0 	1.590899 	0.572359 	0.41 	1.2500 	1.555 	1.9500 		3.58
Color_Intensity 		178.0 	5.058090 	2.318286 	1.28 	3.2200 	4.690 	6.2000 		13.00
Hue 					178.0 	0.957449 	0.228572 	0.48 	0.7825 	0.965 	1.1200 		1.71
OD280 					178.0 	2.611685 	0.709990 	1.27 	1.9375 	2.780 	3.1700 		4.00
Proline 				178.0 	746.893258 	314.907474 	278.00 	500.500 673.500 985.0000 	1680.00

Patrząc na stół widać, że jest ich trochę zmienność danych – dla niektórych kolumn np. Alchool jest więcej, a dla innych, takich jak Malic_Acid, mniej. Teraz możemy sprawdzić, czy są jakieś nulllub NaN wartości w naszym zbiorze danych:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 13 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Alcohol               178 non-null    float64
 1   Malic_Acid            178 non-null    float64
 2   Ash                   178 non-null    float64
 3   Ash_Alcanity          178 non-null    float64
 4   Magnesium             178 non-null    int64  
 5   Total_Phenols         178 non-null    float64
 6   Flavanoids            178 non-null    float64
 7   Nonflavanoid_Phenols  178 non-null    float64
 8   Proanthocyanins       178 non-null    float64
 9   Color_Intensity       178 non-null    float64
 10  Hue                   178 non-null    float64
 11  OD280                 178 non-null    float64
 12  Proline               178 non-null    int64  
dtypes: float64(11), int64(2)
memory usage: 18.2 KB

Nie ma potrzeby upuszczania ani wprowadzania danych, biorąc pod uwagę, że w zestawie danych nie ma pustych wartości. Możemy użyć Seaborn pairplot() aby zobaczyć rozkład danych i sprawdzić, czy zbiór danych tworzy pary kolumn, które mogą być interesujące dla klastrowania:

sns.pairplot(df)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Patrząc na wykres pary, dwie kolumny wydają się obiecujące dla celów grupowania – Alcohol i OD280 (co jest metodą oznaczania stężenia białka w winach). Wydaje się, że na działkach łączących dwa z nich znajdują się 3 odrębne skupiska.

Istnieją również inne kolumny, które wydają się być ze sobą skorelowane. Przede wszystkim Alcohol i Total_Phenols, Alcohol i Flavanoids. Mają świetne liniowe zależności, które można zaobserwować na wykresie pary.

Ponieważ skupiamy się na grupowaniu przy użyciu K-średnich, wybierzmy jedną parę kolumn, powiedzmy Alcohol i OD280i przetestuj metodę kolankową dla tego zestawu danych.

Uwaga: W przypadku korzystania z większej liczby kolumn zbioru danych konieczne będzie wykreślenie w 3 wymiarach lub zmniejszenie danych do główne składniki (zastosowanie PCA). Jest to prawidłowe i bardziej powszechne podejście, po prostu upewnij się, że wybierasz główne komponenty na podstawie tego, jak wiele wyjaśniają i pamiętaj, że przy zmniejszaniu wymiarów danych następuje pewna utrata informacji – więc wykres jest przybliżenie prawdziwych danych, a nie tego, jaka jest naprawdę.

Narysujmy wykres rozrzutu z tymi dwiema kolumnami ustawionymi jako jego oś, aby przyjrzeć się bliżej punktom, które chcemy podzielić na grupy:

sns.scatterplot(data=df, x='OD280', y='Alcohol')

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Teraz możemy zdefiniować nasze kolumny i użyć metody łokcia do określenia liczby skupień. Zainicjujemy również algorytm za pomocą kmeans++ tylko po to, aby szybciej się zbieżność:

values = df[['OD280', 'Alcohol']]

wcss_wine = [] 
for i in range(1, 11): 
    kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
    kmeans.fit(values) 
    wcss_wine.append(kmeans.inertia_)

Obliczyliśmy WCSS, więc możemy wykreślić wyniki:

clusters_wine = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(clusters_wine, wcss_wine)
plt.axvline(3, linestyle='--', color='r')

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Zgodnie z metodą łokcia powinniśmy mieć tutaj 3 skupiska. W ostatnim kroku zgrupujmy nasze punkty w 3 skupienia i wykreślmy te skupienia oznaczone kolorami:

kmeans_wine = KMeans(n_clusters=3, random_state=42)
kmeans_wine.fit(values)
sns.scatterplot(x = values['OD280'], y = values['Alcohol'], hue=kmeans_wine.labels_)

Ostateczny przewodnik po klastrowaniu K-Means za pomocą Scikit-Learn PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Widzimy klastry 0, 1, 2 na wykresie. Na podstawie naszej analizy grupa 0 ma wina o wyższej zawartości białka i niższej zawartości alkoholu, grupa 1 ma wina o wyższej zawartości alkoholu i niskiej zawartości białka oraz grupa 2 ma w swoich winach zarówno wysokobiałkowe, jak i wysokoalkoholowe.

To bardzo ciekawy zestaw danych i zachęcam do głębszego zagłębienia się w analizę poprzez grupowanie danych po normalizacji i PCA – również poprzez interpretację wyników i znalezienie nowych połączeń.

Wnioski

K-średnie klastrowanie to prosty, ale bardzo skuteczny nienadzorowany algorytm uczenia maszynowego do grupowania danych. Grupuje dane na podstawie odległości euklidesowej między punktami danych. Algorytm grupowania K-Means ma wiele zastosowań do grupowania dokumentów tekstowych, obrazów, filmów i wielu innych.

Znak czasu:

Więcej z Nadużycie stosu