1. Wstęp

W tej pracy zostało przedstawione 5 metod klastrowania na danych dotyczących ludności i wydatków samorządowych. Do klastrowania i wizualizacji zostały wykorzystane biblioteki cluster i factoextra.

W projekcie sztuczna inteligencja została wykorzystana do pomocy w przygotowaniu kodu.

library(cluster)
library(factoextra)

2. Dane

Zbiór danych wykorzystany w tej pracy pochodzi z platformy statystycznej GUS (stat.gov.pl). Jest on połączeniem informacji o gęstości zaludnienia i średnich wydatkach samorządów gminnych na jedną osobę w każdym z 380 powiatów w 2024 roku.

data <- read.csv("data_1.csv", sep = ";", dec = ".", header = TRUE, encoding = "UTF-8")
head(data)
##           powiat gestosc wydatki
## 1  boleslawiecki    66.9 8228.67
## 2 dzierzoniowski   196.2 7084.13
## 3      glogowski   190.4 8771.87
## 4       gorowski    43.4 7505.08
## 5       jaworski    80.6 8259.85
## 6     karkonoski    95.5 9986.58

Poniżej znajdują się podstawowe statystyki dotyczące zawartych danych:

summary(data)
##     powiat             gestosc           wydatki     
##  Length:380         Min.   :  17.90   Min.   : 6562  
##  Class :character   1st Qu.:  56.58   1st Qu.: 7695  
##  Mode  :character   Median :  88.05   Median : 8210  
##                     Mean   : 341.41   Mean   : 8616  
##                     3rd Qu.: 179.85   3rd Qu.: 9066  
##                     Max.   :3603.70   Max.   :17188

Na potrzeby klastrowania został wydzielony podzbiór zawierający same dane liczbowe.

num_data <- data[, 2:3]

Do pomiaru możliwości klastrowania na tych danych została wykorzystana statystyka Hopkinsa. Jej wartość bliska 0 oznacza jednostajnie rozłożone dane, wartość bliska 0.5 oznacza losowe dane, zaś wartość bliska 1 oznacza możliwość klastrowania. Dla badanego zbioru danych została uzyskana statystyka powyżej 0.9, co daje wysokie prawdopodobieństwo istotnego klastrowania.

hop <- get_clust_tendency(num_data, ceiling(nrow(num_data)/2), graph = TRUE)
hop$hopkins_stat
## [1] 0.9010756
hop$plot

3. Klastrowanie

Na przedstawionych danych zostało przeprowadzone klastrowanie trzema zwykłymi metodami (K-means, PAM i CLARA) oraz dwiema metodami klastrowania hierarchicznego (AGNES i DIANA). W przypadku zwykłych metod liczba klastrów została dobrana automatycznie przy pomocy statystyki Gap, zaś dla klastrowania hierarchicznego została wykorzystana stała liczba klastrów. W każdym przypadku do pomiaru jakości klastrowania została wykorzystana statystyka Silhouette.

3.1. K-means

W metodzie K-means minimalizuje się sumę kwadratów odległości między punktami danych a środkami klastrów (centroidami), które mogą być dowolnymi punktami i nie muszą należeć do zbioru. Centroidy są wyszukiwane iteracyjną metodą losowania i poprawiania ich z każdym krokiem. Dla badanych danych jako najlepsza liczba zostało dopasowane 6 klastrów, a miara Silhouette wyniosła 0.47.

kmeans <- eclust(num_data, "kmeans", k.max = 10, graph = FALSE)
fviz_cluster(kmeans, geom = "point", main = "K-means", palette = "Set1")

fviz_silhouette(kmeans)
##   cluster size ave.sil.width
## 1       1   26          0.49
## 2       2   94          0.53
## 3       3  127          0.50
## 4       4   27          0.17
## 5       5   74          0.50
## 6       6   32          0.27

3.2. PAM

PAM (Partitioning Around Medoids) jest zmodyfikowaną wersją algorytmu k-means, w której środkami klastrów są konkretne obserwacje ze zbioru danych (medoidy). Algorytm również polega na losowym dobraniu początkowych medoidów spośród wszystkich danych, a następnie iteracyjne poprawianie ich do minimalizacji odległości. Podobnie jak w przypadku poprzedniej metody, zostało dopasowane 6 klastrów, jednak z pewnymi rożnicami w przypisaniu poszczególnych obserwacji do klastrów.

pam <- eclust(num_data, "pam", k.max = 10, graph = FALSE)
fviz_cluster(pam, geom = "point", main = "PAM", palette = "Set1")

fviz_silhouette(pam)
##   cluster size ave.sil.width
## 1       1  115          0.53
## 2       2   99          0.49
## 3       3   78          0.49
## 4       4   26          0.50
## 5       5   34          0.20
## 6       6   28          0.30

3.3. CLARA

CLARA (Clustering Large Applications) to metoda klastrowania zaprojektowana dla dużych zbiorów danych, która optymalizuje algorytm PAM poprzez wykonywanie obliczeń na wielokrotnie losowanych próbkach zamiast na całym zbiorze danych. Dzięki temu rozwiązaniu algorytm zachowuje odporność na wartości odstające, jednocześnie redukując złożoność obliczeniową. Dla badanego zbioru danych zostały otrzymane tą metodą 4 klastry z miarą Silhouette 0.44.

clara <- eclust(num_data, "clara", k.max = 10, graph = FALSE)
fviz_cluster(clara, geom = "point", main = "CLARA", palette = "Set1")

fviz_silhouette(clara)
##   cluster size ave.sil.width
## 1       1  149          0.51
## 2       2  107          0.57
## 3       3   71          0.21
## 4       4   53          0.31

3.4. AGNES

Klastrowanie hierarchiczne jest metodą budującą strukturę w formie drzewa, obrazującą stopień podobieństwa między obiektami. W przeciwieństwie do zwykłych metod nie wymaga ono określenia liczby klastrów a priori. Podstawowym algorytmem jest klastrowanie aglomeracyjne, w którym na początku każda obserwacja jest swoim własnym klastrem, a w każdej iteracji najbardziej podobne z nich są łączone, aż do uzyskania jednej struktury. Następnie można dobrać pożądaną liczbę klastrów lub stopień podobieństwa między nimi. Przykładem jest metoda AGNES (Agglomerative Nesting), przy użyciu której został uzyskany inny podział zbioru danych dla 6 klastrów - najbardziej zauważalne jest wydzielenie dwóch powiatów z największą średnią wydatków do osobnego klastra. Został też uzyskany niższy wynik Silhouette niż w poprzednich metodach.

agnes <- eclust(num_data, "agnes", k = 6, graph = FALSE)
fviz_cluster(agnes, geom = "point", main = "AGNES", palette = "Set1")

fviz_dend(agnes, palette = "Set1", main = "AGNES Dendrogram", show_labels = FALSE)

fviz_silhouette(agnes)
##   cluster size ave.sil.width
## 1       1  107          0.66
## 2       2  112          0.44
## 3       3   95          0.18
## 4       4   37          0.40
## 5       5   27          0.27
## 6       6    2          0.29

3.5. DIANA

DIANA (Divisive Analysis) to metoda podziałowego klastrowania hierarchicznego, która w przeciwieństwie do AGNES rozpoczyna proces od jednego dużego klastra i iteracyjnie dzieli go na mniejsze. W tym przypadku zdecydowana większość obserwacji została przyporządkowana do jednego klastra, zaś powiat z największymi średnimi wydatkami (m. Sopot) jest jedyną obserwacją w swoim klastrze. Ta metoda dała jednak zdecydowanie najwyższą wartość Silhouette równą 0.6.

diana <- eclust(num_data, "diana", k = 6, graph = FALSE)
fviz_cluster(diana, geom = "point", main = "DIANA", palette = "Set1")

fviz_dend(diana, palette = "Set1", main = "DIANA Dendrogram", show_labels = FALSE)

fviz_silhouette(diana)
##   cluster size ave.sil.width
## 1       1  304          0.67
## 2       2   31          0.28
## 3       3   17          0.37
## 4       4   24          0.38
## 5       5    3          0.26
## 6       6    1          0.00

data$powiat[diana$cluster == 6]
## [1] "m. Sopot"

Warto również zauważyć, że do klastrów 3-6 zostały przyporządkowane jedynie miasta na prawach powiatu - są to obserwacje z najwyższymi gęstościami zaludnienia. Nie da się jednak pomiędzy nimi dostrzec powiązań geograficznych.

data$powiat[diana$cluster == 3]
##  [1] "m. Legnica"             "m. Bydgoszcz"           "m. Torun"              
##  [4] "m. Chelm"               "m. Lublin"              "m. Gorzow Wielkopolski"
##  [7] "m. Skierniewice"        "m. Tarnow"              "m. Bialystok"          
## [10] "m. lomza"               "m. Chorzow"             "m. Czestochowa"        
## [13] "m. swietochlowice"      "m. Tychy"               "m. Zabrze"             
## [16] "m. Koszalin"            "m. Szczecin"
data$powiat[diana$cluster == 4]
##  [1] "m. Wroclaw"        "m. Walbrzych"      "m. Grudziadz"     
##  [4] "m. Wloclawek"      "m. Biala Podlaska" "m. Zamosc"        
##  [7] "m. lodz"           "m. Krakow"         "m. Nowy Sacz"     
## [10] "m. Ostroleka"      "m. Radom"          "m. Siedlce"       
## [13] "m. Przemysl"       "m. Rzeszow"        "m. Suwalki"       
## [16] "m. Slupsk"         "m. Bielsko-Biala"  "m. Gliwice"       
## [19] "m. Katowice"       "m. Kielce"         "m. Olsztyn"       
## [22] "m. Kalisz"         "m. Leszno"         "m. Poznan"
data$powiat[diana$cluster == 5]
## [1] "m. Plock"        "m. st. Warszawa" "m. Krosno"