V tejto úlohe robím klastrovú (zhlukovú) analýzu, a používam databázu
World Happiness Report 2019, ktorú mám uloženú v
priečinku udaje ako 2019.csv. Cieľom je
zoskupiť krajiny podľa podobnosti v základných socio-ekonomických a
zdravotných ukazovateľoch. Týmto spôsobom viem nájsť “podobné” krajiny a
pochopiť, ktoré faktory ich robia blízkymi alebo odlišnými.
knitr::opts_chunk$set(
echo = TRUE,
message = TRUE,
warning = FALSE,
error = FALSE
)
library(knitr)
library(kableExtra)
library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:kableExtra':
##
## group_rows
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(cluster)
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(stats)
rm(list = ls())
Pracujem so všetkými krajinami dostupnými v roku 2019. Pre jednoduchosť však ponechám len premenné, ktoré sú dobre interpretovateľné a použiteľné v klastrovej analýze a to:
udaje_raw <- read.csv("udaje/2019.csv", sep = ",", dec = ".", header = TRUE)
names(udaje_raw) <- make.names(names(udaje_raw))
udaje <- udaje_raw[, c("Country.or.region",
"Score",
"GDP.per.capita",
"Social.support",
"Healthy.life.expectancy")]
rownames(udaje) <- udaje$Country.or.region
udaje$Country.or.region <- NULL
summary(udaje)
## Score GDP.per.capita Social.support Healthy.life.expectancy
## Min. :2.853 Min. :0.0000 Min. :0.000 Min. :0.0000
## 1st Qu.:4.545 1st Qu.:0.6028 1st Qu.:1.056 1st Qu.:0.5477
## Median :5.380 Median :0.9600 Median :1.272 Median :0.7890
## Mean :5.407 Mean :0.9051 Mean :1.209 Mean :0.7252
## 3rd Qu.:6.184 3rd Qu.:1.2325 3rd Qu.:1.452 3rd Qu.:0.8818
## Max. :7.769 Max. :1.6840 Max. :1.624 Max. :1.1410
Musím premenné preškálovať, aby boli na rovnakej škále.
udaje_scaled <- scale(udaje)
summary(udaje_scaled)
## Score GDP.per.capita Social.support Healthy.life.expectancy
## Min. :-2.29454 Min. :-2.2720 Min. :-4.0403 Min. :-2.9953
## 1st Qu.:-0.77494 1st Qu.:-0.7590 1st Qu.:-0.5116 1st Qu.:-0.7331
## Median :-0.02479 Median : 0.1377 Median : 0.2095 Median : 0.2633
## Mean : 0.00000 Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.69840 3rd Qu.: 0.8217 3rd Qu.: 0.8145 3rd Qu.: 0.6464
## Max. : 2.12188 Max. : 1.9550 Max. : 1.3877 Max. : 1.7171
num_vars <- as.data.frame(udaje_scaled)
num_plots <- ncol(num_vars)
par(mfrow = c(2,2))
par(mar = c(4,4,2,1))
for (col in names(num_vars)) {
boxplot(num_vars[[col]],
main = col,
col = "lightblue",
horizontal = TRUE)
}
mtext("Boxploty škálovaných premenných (World Happiness 2019)", outer = TRUE, cex = 1.3, font = 2)
Niektoré krajiny majú extrémne hodnoty, ale tie ponechávam pretože ide o reálne rozdiely.
Korelačná matica ukazuje, ako spolu jednotlivé premenné súvisia. V mojom prípade sú všetky korelácie stredne vysoké (okolo 0.72–0.84), čo znamená, že premenné medzi sebou súvisia, ale nie príliš silno.
Dôležité je, že žiadna korelácia nepresiahla hodnotu 0.9, čo je hranica, pri ktorej by som už musela jednu premennú vylúčiť (pretože by boli takmer totožné). Keďže tu žiadna premenná túto hranicu nepresiahla, môžem si bez problémov ponechať všetky premenné v ďalšej analýze.
Najsilnejšie súvislosti sú medzi:
Čo dáva aj intuitívny zmysel — bohatšie a zdravšie krajiny majú väčšinou aj vyšší index šťastia.
cor_mat <- cor(udaje_scaled)
round(cor_mat, 2)
## Score GDP.per.capita Social.support
## Score 1.00 0.79 0.78
## GDP.per.capita 0.79 1.00 0.75
## Social.support 0.78 0.75 1.00
## Healthy.life.expectancy 0.78 0.84 0.72
## Healthy.life.expectancy
## Score 0.78
## GDP.per.capita 0.84
## Social.support 0.72
## Healthy.life.expectancy 1.00
Matica vzdialeností ukazuje, ako ďaleko sú od seba krajiny. Je to základný krok klastrovej analýzy, pretože podľa týchto vzdialeností algoritmus zlučuje podobné krajiny. Kedže mám dáta sa vyše ako 100 krajín, vypíšem na ukážku len prvých 10. Krajiny s podobnými hodnotami sú si bližšie, vzdialenejšie krajiny majú protikladné charakteristiky.
dist_mat <- dist(udaje_scaled, method = "euclidean")
as.matrix(dist_mat)[1:10, 1:10] # výpis prvých 10x10
## Finland Denmark Norway Iceland Netherlands Switzerland
## Finland 0.0000000 0.1964592 0.4535258 0.3371978 0.3654694 0.5121674
## Denmark 0.1964592 0.0000000 0.2992397 0.2313732 0.2009944 0.3461069
## Norway 0.4535258 0.2992397 0.0000000 0.3101135 0.3337759 0.2396738
## Iceland 0.3371978 0.2313732 0.3101135 0.0000000 0.3609749 0.3894104
## Netherlands 0.3654694 0.2009944 0.3337759 0.3609749 0.0000000 0.2605853
## Switzerland 0.5121674 0.3461069 0.2396738 0.3894104 0.2605853 0.0000000
## Sweden 0.5302072 0.3727102 0.4551738 0.4830257 0.1813002 0.3004991
## New Zealand 0.4671600 0.3575233 0.5214677 0.3401867 0.3271924 0.4316273
## Canada 0.5670453 0.4109969 0.4744478 0.4473830 0.2686413 0.2973733
## Austria 0.6200076 0.4642849 0.5347466 0.5472277 0.2817677 0.3629715
## Sweden New Zealand Canada Austria
## Finland 0.5302072 0.4671600 0.5670453 0.6200076
## Denmark 0.3727102 0.3575233 0.4109969 0.4642849
## Norway 0.4551738 0.5214677 0.4744478 0.5347466
## Iceland 0.4830257 0.3401867 0.4473830 0.5472277
## Netherlands 0.1813002 0.3271924 0.2686413 0.2817677
## Switzerland 0.3004991 0.4316273 0.2973733 0.3629715
## Sweden 0.0000000 0.3243025 0.1594709 0.1039263
## New Zealand 0.3243025 0.0000000 0.2408075 0.3367499
## Canada 0.1594709 0.2408075 0.0000000 0.1437587
## Austria 0.1039263 0.3367499 0.1437587 0.0000000
Najbližšie k sebe majú krajiny ako Fínsko, Dánsko, Švajčiarsko, Holandsko, Island či Švédsko. Je to logické, keďže patria medzi najvyspelejšie štáty a dosahujú veľmi podobné hodnoty vo všetkých sledovaných ukazovateľoch. Napríklad vzdialenosť Fínsko – Dánsko je iba 0.19, čo znamená vysokú podobnosť. Naopak, vzdialenosti okolo 0.5–0.6 už naznačujú výrazné rozdiely medzi krajinami.
hc <- hclust(dist_mat, method = "ward.D2")
k <- 3
klastre <- cutree(hc, k = k)
library(factoextra)
fviz_dend(hc,
k = k,
cex = 0.25, # ešte menšie písmo
horiz = FALSE,
k_colors = c("red","blue","darkgreen"),
main = "Hierarchické zhlukovanie – World Happiness 2019")
Pri vytváraní dendrogramu som najprv použila základný príkaz plot(hc) tak ako v príklade od Vás. Keďže však môj dataset World Happiness 2019 obsahuje výrazne viac krajín (okolo 150), výsledný dendrogram bol nečitateľný – názvy krajín sa prekrývali a nebolo možné určiť klastre. Preto som použila funkciu fviz_dend() z balíka factoextra, ktorá umožňuje zmenšiť veľkosť textu, pridať farby pre jednotlivé klastre a zlepšiť čitateľnosť grafu.Na prvý pohľad je to stále nečítateľné ale po priblížení sa to dá. :) Takto upravený dendrogram je prehľadný a dá sa z neho interpretovať členenie krajín. Pri tomto mi pomohol ChatGPT.
Krajiny sa prirodzene rozdelili do troch veľmi logických klastrov. Prvý klaster(červený) zahŕňa najšťastnejšie a ekonomicky najrozvinutejšie štáty, najmä severské krajiny, Holandsko, Švajčiarsko a Kanadu. Druhý klaster(modrý) predstavuje stredne rozvinuté európske krajiny a niektoré štáty so zmiešaným profilom. Tretí klaster(zelený) tvorí skupina najchudobnejších krajín, prevažne z Afriky a južnej Ázie, s najnižšími hodnotami všetkých sledovaných ukazovateľov. Celkový výsledok dobre vystihuje globálne rozdiely v kvalite života a potvrdzuje, že štáty sa prirodzene zhlukujú podľa socio-ekonomických charakteristík.
ssq <- function(x, m) sum((x - m)^2)
var_names <- colnames(udaje_scaled)
TSS <- sapply(var_names, function(v) ssq(udaje_scaled[, v], mean(udaje_scaled[, v])))
WSS <- sapply(var_names, function(v) {
x <- udaje_scaled[, v]
tapply(x, klastre, function(z) ssq(z, mean(z))) |> sum()
})
BSS <- TSS - WSS
ss_table <- data.frame(
Variable = var_names,
TSS = TSS,
WSS = WSS,
BSS = BSS,
Prop_Between = BSS / TSS
)
ss_table
## Variable TSS WSS BSS
## Score Score 155 41.47753 113.52247
## GDP.per.capita GDP.per.capita 155 32.27353 122.72647
## Social.support Social.support 155 62.63249 92.36751
## Healthy.life.expectancy Healthy.life.expectancy 155 47.98130 107.01870
## Prop_Between
## Score 0.7324030
## GDP.per.capita 0.7917837
## Social.support 0.5959194
## Healthy.life.expectancy 0.6904432
Na základe hodnoty Prop_Between môžem konštatovať, že najvýraznejšie odlišujú klastre premenné GDP per capita, Score a Healthy life expectancy, zatiaľ čo premenná Social support má najnižšiu separačnú schopnosť. To znamená, že ekonomická úroveň a zdravotný stav sú hlavné faktory, ktoré rozdeľujú krajiny sveta do jednotlivých klastrov v roku 2019.
Z porovnania centroidov jasne vidieť, že klastre reprezentujú tri úrovne rozvoja – vysokú, strednú a nízku – a rozdelenie krajín teda veľmi dobre odráža ich reálnu socio-ekonomickú situáciu.
udaje_centroids <- data.frame(udaje, klaster = klastre)
deskriptiva <- udaje_centroids %>%
group_by(klaster) %>%
summarise(
Score = mean(Score),
GDP = mean(GDP.per.capita),
Social = mean(Social.support),
Health = mean(Healthy.life.expectancy)
)
deskriptiva
## # A tibble: 3 × 5
## klaster Score GDP Social Health
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 6.50 1.28 1.44 0.935
## 2 2 5.10 0.842 1.19 0.698
## 3 3 3.98 0.317 0.805 0.383
V tejto úlohe som pomocou hierarchickej klastrovej analýzy rozdelila krajiny sveta za rok 2019 do troch logických skupín. Ukázalo sa, že najsilnejšie oddeľujúce premenné sú HDP na obyvateľa, sociálna opora a zdravá dĺžka života, čo dáva aj intuitívne zmysel – bohaté krajiny s kvalitným zdravotníctvom tvorili samostatný klaster. Naopak, menej rozvinuté štáty skončili spolu v klusteri s nižšími hodnotami všetkých premenných. Táto analýza ukazuje, že aj jednoduchá klastrová metóda dokáže veľmi dobre identifikovať skupiny podobných krajín na základe socio-ekonomických ukazovateľov a môže byť užitočná pri porovnávaní svetových regiónov alebo plánovaní politík.
Dnešné zadanie ma bavilo a malo aj zaujímavý výsledok. Teším sa na ďalšie. Vanessa