1. Úvod

Cieľom tohto cvičenia je vykonať zhlukovú analýzu na prierezových údajoch.
Ako príklad používam mieru nezamestnanosti v roku 2024 pre tri európske krajiny:

Každý riadok v dátach predstavuje jednu krajinu a premennou záujmu je miera nezamestnanosti v % z pracovnej sily.
Pôvodné dáta mali panelový charakter (viaceré roky), ale pre účely tejto úlohy som si vybrala iba rok 2024, čím vznikli prierezové údaje.

2. Načítanie údajov a tvorba prierezového súboru

V tejto časti načítam CSV súbor z Eurostatu (une_rt_a__custom_18708117_linear.csv) a vytvorím prierezový dataset pre rok 2024.

rm(list = ls())

library(dplyr)
library(knitr)
library(kableExtra)

# upravím si cestu k súboru podľa seba
udaje <- read.csv("une_rt_a__custom_18708117_linear.csv",
                  stringsAsFactors = FALSE)

str(udaje)
## 'data.frame':    33 obs. of  11 variables:
##  $ DATAFLOW   : chr  "ESTAT:UNE_RT_A(1.0)" "ESTAT:UNE_RT_A(1.0)" "ESTAT:UNE_RT_A(1.0)" "ESTAT:UNE_RT_A(1.0)" ...
##  $ LAST.UPDATE: chr  "11/09/25 23:00:00" "11/09/25 23:00:00" "11/09/25 23:00:00" "11/09/25 23:00:00" ...
##  $ freq       : chr  "Annual" "Annual" "Annual" "Annual" ...
##  $ age        : chr  "From 15 to 74 years" "From 15 to 74 years" "From 15 to 74 years" "From 15 to 74 years" ...
##  $ unit       : chr  "Percentage of population in the labour force" "Percentage of population in the labour force" "Percentage of population in the labour force" "Percentage of population in the labour force" ...
##  $ sex        : chr  "Total" "Total" "Total" "Total" ...
##  $ geo        : chr  "Czechia" "Czechia" "Czechia" "Czechia" ...
##  $ TIME_PERIOD: int  2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 ...
##  $ OBS_VALUE  : num  6.1 5.1 4 2.9 2.2 2 2.6 2.8 2.2 2.6 ...
##  $ OBS_FLAG   : chr  "" "" "" "" ...
##  $ CONF_STATUS: logi  NA NA NA NA NA NA ...
head(udaje)
##              DATAFLOW       LAST.UPDATE   freq                 age
## 1 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
## 2 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
## 3 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
## 4 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
## 5 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
## 6 ESTAT:UNE_RT_A(1.0) 11/09/25 23:00:00 Annual From 15 to 74 years
##                                           unit   sex     geo TIME_PERIOD
## 1 Percentage of population in the labour force Total Czechia        2014
## 2 Percentage of population in the labour force Total Czechia        2015
## 3 Percentage of population in the labour force Total Czechia        2016
## 4 Percentage of population in the labour force Total Czechia        2017
## 5 Percentage of population in the labour force Total Czechia        2018
## 6 Percentage of population in the labour force Total Czechia        2019
##   OBS_VALUE OBS_FLAG CONF_STATUS
## 1       6.1                   NA
## 2       5.1                   NA
## 3       4.0                   NA
## 4       2.9                   NA
## 5       2.2                   NA
## 6       2.0                   NA

Vyberiem iba rok 2024 a premenné, ktoré potrebujem:

udaje2024 <- udaje %>%
  dplyr::filter(TIME_PERIOD == 2024) %>%
  dplyr::select(
    Country = geo,
    Unemployment = OBS_VALUE
  )

# nastavím názvy riadkov podľa krajín
rownames(udaje2024) <- udaje2024$Country
udaje2024$Country <- NULL

kable(udaje2024,
      caption = "Prierezové údaje – miera nezamestnanosti v roku 2024 (v %)",
      digits = 1) %>%
  kable_styling(full_width = FALSE)
Prierezové údaje – miera nezamestnanosti v roku 2024 (v %)
Unemployment
Czechia 2.6
Germany 3.4
Slovakia 5.3

Komentár:
Dataset je prierezový, pretože:

3. Škálovanie premenných a boxplot

V zhlukovej analýze sa často používa štandardizácia (z-skóre), aby premenné s rôznymi jednotkami či mierkami mali porovnateľný vplyv na vzdialenosti.

V mojom prípade mám iba jednu premennú Unemployment, ale pre úplnosť ju tiež štandardizujem.

# odstránenie prípadných NA (pre istotu)
udaje_complete <- na.omit(udaje2024)

# škálovanie (z-skóre)
udaje_scaled <- scale(udaje_complete)
udaje_scaled <- as.data.frame(udaje_scaled)

kable(udaje_scaled,
      caption = "Škálované hodnoty miery nezamestnanosti (z-skóre)",
      digits = 3) %>%
  kable_styling(full_width = FALSE)
Škálované hodnoty miery nezamestnanosti (z-skóre)
Unemployment
Czechia -0.841
Germany -0.264
Slovakia 1.106

Teraz si zobrazím boxplot škálovaných hodnôt.

boxplot(
  udaje_scaled$Unemployment,
  main = "Škálovaná miera nezamestnanosti (z-skóre)",
  ylab = "Unemployment (z-skóre)"
)

Komentár:
Keďže mám len 3 krajiny, boxplot je skôr ilustračný. Napriek tomu ukazuje, či niektorá krajina výraznejšie „vyčnieva“ (má vyššiu alebo nižšiu nezamestnanosť v porovnaní s ostatnými).

4. Korelačná matica a matica vzdialeností

Pri viacerých premenných by som skúmala korelačnú maticu.
Tu mám iba jednu premennú, takže korelácia je triviálne rovná 1.

cor_mat <- cor(udaje_scaled, use = "pairwise.complete.obs")
round(cor_mat, 2)
##              Unemployment
## Unemployment            1

Dôležitejšia je pre mňa matica vzdialeností medzi krajinami, ktorú použijem v zhlukovaní.
Použijem euklidovskú vzdialenosť.

dist_mat <- dist(udaje_scaled, method = "euclidean")
round(as.matrix(dist_mat), 3)
##          Czechia Germany Slovakia
## Czechia    0.000   0.577    1.947
## Germany    0.577   0.000    1.370
## Slovakia   1.947   1.370    0.000

Komentár:
Matica vzdialeností hovorí, ktoré krajiny sú si podobné z hľadiska miery nezamestnanosti (malá vzdialenosť) a ktoré sú odlišné (väčšia vzdialenosť).

5. Hierarchické zhlukovanie (Wardova metóda)

Na základe matice vzdialeností vykonám hierarchické zhlukovanie pomocou Wardovej metódy (ward.D2).
Wardova metóda minimalizuje vnútroklastrovú variabilitu a je často odporúčaná pri zhlukovaní kvantitatívnych premenných.

Všetko (vykreslenie dendrogramu, obdlžníky okolo klastrov aj priradenie klastrov) dávam do jedného chunka, aby nedochádzalo k chybe plot.new has not been called yet.

# hierarchické zhlukovanie
hc <- hclust(dist_mat, method = "ward.D2")

# vykreslenie dendrogramu
plot(
  hc,
  main = "Hierarchické zhlukovanie krajín podľa miery nezamestnanosti (Ward)",
  xlab = "",
  sub = ""
)

# zvolím počet klastrov
k <- 2

# dokreslím obdlžníky okolo klastrov
rect.hclust(hc, k = k, border = "red")

# priradenie krajín do klastrov
klaster_membership <- cutree(hc, k = k)
klaster_membership
##  Czechia  Germany Slovakia 
##        1        1        2

Teraz spojím informáciu o klastri s pôvodnými (neškálovanými) hodnotami nezamestnanosti:

udaje_clust <- udaje_complete
udaje_clust$klaster <- factor(klaster_membership)

kable(udaje_clust,
      caption = "Priradenie krajín do klastrov",
      digits = 1) %>%
  kable_styling(full_width = FALSE)
Priradenie krajín do klastrov
Unemployment klaster
Czechia 2.6 1
Germany 3.4 1
Slovakia 5.3 2

Komentár:
- Krajiny v tom istom klastri majú podobnú mieru nezamestnanosti.
- Pri malom počte krajín (tu 3) ide skôr o ilustračný príklad zhlukovania, ale postup je identický ako pri väčšom počte objektov.

6. Deskriptívne štatistiky podľa klastra

Ďalej vypočítam základné deskriptívne štatistiky miery nezamestnanosti pre jednotlivé klastry.

descriptives <- udaje_clust %>%
  dplyr::group_by(klaster) %>%
  dplyr::summarise(
    n = dplyr::n(),
    mean_unemp = mean(Unemployment),
    sd_unemp   = sd(Unemployment),
    min_unemp  = min(Unemployment),
    max_unemp  = max(Unemployment)
  )

kable(descriptives,
      caption = "Deskriptívne štatistiky miery nezamestnanosti podľa klastrov",
      digits = 2) %>%
  kable_styling(full_width = FALSE)
Deskriptívne štatistiky miery nezamestnanosti podľa klastrov
klaster n mean_unemp sd_unemp min_unemp max_unemp
1 2 3.0 0.57 2.6 3.4
2 1 5.3 NA 5.3 5.3

Komentár:
Z tabuľky vidno, či sú klastry od seba jasne odlíšiteľné – napríklad jeden klaster môže mať nižšiu priemernú nezamestnanosť a druhý vyššiu.

7. Rozklad variability (TSS, WSS, BSS)

Na záver vypočítam rozklad variability:

Najprv si definujem pomocnú funkciu na sumu štvorcov:

ssq <- function(x, m) sum((x - m)^2)

var_names <- colnames(udaje_scaled)

# Celková suma štvorcov (TSS) pre každú premennú
TSS <- sapply(var_names, function(v) {
  ssq(udaje_scaled[, v], mean(udaje_scaled[, v]))
})

# Vnútroklastrová suma štvorcov (WSS)
WSS <- sapply(var_names, function(v) {
  x <- udaje_scaled[, v]
  tapply(x, klaster_membership, function(z) ssq(z, mean(z))) |> sum()
})

# Medziklastrová suma štvorcov (BSS)
BSS <- TSS - WSS

variab_tab <- data.frame(
  Variable      = var_names,
  TSS           = TSS,
  WSS           = WSS,
  BSS           = BSS,
  BSS_over_TSS  = BSS / TSS
)

kable(variab_tab,
      digits = 3,
      caption = "Rozklad variability pre mieru nezamestnanosti") %>%
  kable_styling(full_width = FALSE)
Rozklad variability pre mieru nezamestnanosti
Variable TSS WSS BSS BSS_over_TSS
Unemployment Unemployment 2 0.166 1.834 0.917

Komentár:

8. Záver

V cvičení som vykonala zhlukovú analýzu prierezových údajov o miere nezamestnanosti v roku 2024 pre tri krajiny: Czechia, Germany a Slovakia.
Najprv som z panelových údajov (viaceré roky) vytvorila prierezový dataset pre jeden rok, čím som splnila podmienku zadania na prierezové údaje. Potom som premennú štandardizovala, vypočítala maticu vzdialeností a pomocou Wardovej metódy vykonala hierarchické zhlukovanie.

Postup v skratke:

Rovnaký postup je možné použiť aj na bohatší dataset s väčším počtom krajín a premenných, kde je zhluková analýza užitočným nástrojom na identifikáciu skupín podobných objektov.