Výber databázy: NBA – štatistiky hráčov v zápasoch, sezóna 2025/26

Zadanie: výber databázy pre ďalšiu prácu

Author

Bc. Richard Vladyka (v spolupráci s claude.ai)

Published

January 1, 2026

1 Výber databázy

Pre ďalšie hodiny som si zvolil databázu NBA Player Stats – Season 25/26, ktorá obsahuje štatistiky jednotlivých hráčov Národnej basketbalovej asociácie (NBA) zo všetkých odohraných zápasov sezóny 2025/26. Súbor som stiahol z platformy Kaggle (Kaggle Datasets) a uložil ako nba_dailyleaders_full.csv; ide o jeden súbor vo formáte CSV.

28 716záznamov (výkonov hráčov)
582hráčov
30tímov
212dní so zápasmi
21. 10. 2025 – 13. 6. 2026sledované obdobie

1.1 Čo databáza obsahuje

Jeden riadok predstavuje výkon jedného hráča v jednom zápase. Databáza má 28 716 záznamov, 582 rôznych hráčov a 30 tímov. Údaje sú zoradené v čase: pokrývajú obdobie od 21. 10. 2025 do 13. 6. 2026 (212 rôznych dní), teda základnú časť aj play-off. To spĺňa požiadavku, aby databáza obsahovala údaje zoradené v čase.

Hlavné premenné (názvy sú už v upravenej podobe, ktorú používam v ďalšej práci):

Premenná Význam
player, tm, opp hráč, jeho tím, súper
result výsledok zápasu pre tím hráča (W – výhra, L – prehra)
date dátum zápasu
mp odohrané minúty
fg, fga, fg_percent úspešné strely z hry, pokusené strely z hry, úspešnosť streľby z hry
p3fg, p3fga, p3fg_percent trojkové strely: úspešné, pokusené, úspešnosť
ft, fta, ft_percent trestné hody: úspešné, pokusené, úspešnosť
orb, drb, trb doskoky (ofenzívne, defenzívne, spolu)
ast, stl, blk, tov, pf asistencie, zisky, bloky, straty, fauly
pts body
plus_minus rozdiel skóre počas hráčovej prítomnosti na ihrisku (+/-)
gm_sc Game Score, súhrnná miera výkonu v zápase

1.2 Čo s ňou plánujem robiť

Databáza je vhodná na hlbšiu analýzu, napríklad:

  • vývoj výkonnosti hráčov a tímov v priebehu sezóny (trend v čase),
  • porovnanie základnej časti a play-off,
  • vplyv odohraných minút a úspešnosti streľby na body a Game Score,
  • porovnanie domácich a hosťujúcich tímov, tímov podľa výsledku zápasu,
  • regresný model pre Game Score alebo body.

2 Import údajov

Údaje som importoval zo súboru CSV. Nižšie je ukážka prvých desiatich riadkov v pôvodnej podobe (bez troch úplne prázdnych stĺpcov, ktoré sú súčasťou súboru a v čistení ich odstránim).

Ukážka importovaných údajov (prvých 10 riadkov)
Player Tm Opp Result MP FG FGA FG% 3P 3PA 3P% FT FTA FT% ORB DRB TRB AST STL BLK TOV PF PTS +/- GmSc Date
Luka Dončić LAL GSW L 40:59 17 27 0.630 2 10 0.200 7 10 0.700 0 12 12 9 2 1 3 1 43 -8 38.9 2025-10-21
Alperen Şengün HOU OKC L 48:53 12 24 0.500 5 8 0.625 10 11 0.909 4 7 11 7 2 1 4 5 39 9 33.1 2025-10-21
Jimmy Butler GSW LAL W 34:44 7 14 0.500 1 2 0.500 16 16 1.000 2 3 5 4 1 0 1 4 31 20 27.5 2025-10-21
Shai Gilgeous-Alexander OKC HOU W 47:13 12 26 0.462 1 9 0.111 10 14 0.714 0 5 5 5 2 2 3 2 35 3 24.6 2025-10-21
Austin Reaves LAL GSW L 36:20 9 16 0.563 1 5 0.200 7 10 0.700 1 4 5 9 2 0 5 5 26 -14 20.4 2025-10-21
Chet Holmgren OKC HOU W 38:30 11 17 0.647 2 5 0.400 4 4 1.000 2 5 7 2 0 0 3 6 28 -1 19.4 2025-10-21
Stephen Curry GSW LAL W 32:04 6 14 0.429 3 9 0.333 8 8 1.000 0 1 1 4 3 1 2 3 23 1 19.2 2025-10-21
Jonathan Kuminga GSW LAL W 32:54 6 11 0.545 4 6 0.667 1 2 0.500 3 6 9 6 1 0 2 3 17 4 17.2 2025-10-21
Cason Wallace OKC HOU W 41:39 5 10 0.500 3 8 0.375 1 2 0.500 1 6 7 5 4 0 2 3 14 8 15.4 2025-10-21
Kevin Durant HOU OKC L 47:03 9 16 0.563 0 4 0.000 5 6 0.833 0 9 9 3 0 0 4 6 23 0 13.4 2025-10-21

3 Čistenie údajov

3.1 Názvy premenných

V pôvodných názvoch stĺpcov sa vyskytujú znaky, ktoré v názvoch premenných v R nie sú prípustné (FG%, 3P, +/-). Použijem knižnicu janitor. Názvy, ktoré po úprave nie sú zrozumiteľné alebo začínajú číslicou, premenujem ručne:

  • +/- na plus_minus,
  • trojkové strely (3P, 3PA, 3P%) na p3fg, p3fga a p3fg_percent. Názov nezačína číslicou, takže sa v kóde dá používať bez zvláštnych úprav.
Zobraziť kód
udaje <- clean_names(surove) %>%
  rename(
    plus_minus   = x,
    p3fg         = x3p,
    p3fga        = x3pa,
    p3fg_percent = x3p_percent
  )

data.frame(
  Povodny_nazov = names(surove),
  Novy_nazov    = names(udaje)
) %>%
  kable(caption = "Pôvodné a nové názvy premenných") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2") %>%
  scroll_box(height = "300px")
Pôvodné a nové názvy premenných
Povodny_nazov Novy_nazov
Player player
Tm tm
Opp opp
Result result
MP mp
FG fg
FGA fga
FG% fg_percent
3P p3fg
3PA p3fga
3P% p3fg_percent
FT ft
FTA fta
FT% ft_percent
ORB orb
DRB drb
TRB trb
AST ast
STL stl
BLK blk
TOV tov
PF pf
PTS pts
+/- plus_minus
GmSc gm_sc
Date date
Unnamed: 0 unnamed_0
Unnamed: 1 unnamed_1
Unnamed: 2 unnamed_2

3.2 Chýbajúce hodnoty

Zobraziť kód
chyby <- colSums(is.na(udaje))
chyby[chyby > 0]
  fg_percent p3fg_percent   ft_percent   plus_minus    unnamed_0    unnamed_1 
        1510         5775        12686           30        28716        28716 
   unnamed_2 
       28716 

Tri stĺpce unnamed_0, unnamed_1 a unnamed_2 sú úplne prázdne (28 716 NA z 28 716 záznamov), preto ich odstránim.

Zobraziť kód
udaje <- udaje %>% select(-starts_with("unnamed"))

Chýbajúce hodnoty v stĺpcoch fg_percent, p3fg_percent a ft_percent nevznikli chybou v údajoch. Úspešnosť sa nedá spočítať, ak hráč nemal žiadny pokus. Overím to:

Zobraziť kód
data.frame(
  stlpec           = c("fg_percent", "p3fg_percent", "ft_percent"),
  pocet_NA         = c(sum(is.na(udaje$fg_percent)),
                       sum(is.na(udaje$p3fg_percent)),
                       sum(is.na(udaje$ft_percent))),
  pocet_bez_pokusu = c(sum(udaje$fga == 0),
                       sum(udaje$p3fga == 0),
                       sum(udaje$fta == 0))
)
        stlpec pocet_NA pocet_bez_pokusu
1   fg_percent     1510             1510
2 p3fg_percent     5775             5775
3   ft_percent    12686            12686
NoteZáver: údaje sa neimputujú

Počty sa zhodujú, takže ide o legitímne “nie je k dispozícii” a údaje nebudem imputovať. Imputácia by vymyslela úspešnosť hráčom, ktorí vôbec nestrieľali. V stĺpci plus_minus chýba 30 hodnôt, čo je zanedbateľné (0,1 %), a v analýzach s týmto stĺpcom ich vynechám.

3.3 Typy premenných

Minúty sú zapísané ako text "MM:SS" a dátum treba previesť na dátumový typ.

Zobraziť kód
udaje <- udaje %>%
  mutate(
    mp = sapply(strsplit(mp, ":", fixed = TRUE), function(x)
      as.numeric(x[1]) + as.numeric(x[2]) / 60),
    date   = as.Date(date),
    tm     = as.factor(tm),
    opp    = as.factor(opp),
    result = as.factor(result)
  ) %>%
  arrange(date)

glimpse(udaje)
Rows: 28,716
Columns: 26
$ player       <chr> "Luka Dončić", "Alperen Şengün", "Jimmy Butler", "Shai Gi…
$ tm           <fct> LAL, HOU, GSW, OKC, LAL, OKC, GSW, GSW, OKC, HOU, OKC, HO…
$ opp          <fct> GSW, OKC, LAL, HOU, GSW, HOU, LAL, LAL, HOU, OKC, HOU, OK…
$ result       <fct> L, L, W, W, L, W, W, W, W, L, W, L, W, L, W, W, W, L, L, …
$ mp           <dbl> 40.98333, 48.88333, 34.73333, 47.21667, 36.33333, 38.5000…
$ fg           <dbl> 17, 12, 7, 12, 9, 11, 6, 6, 5, 9, 6, 8, 6, 7, 2, 3, 3, 3,…
$ fga          <dbl> 27, 24, 14, 26, 16, 17, 14, 11, 10, 16, 12, 17, 11, 15, 5…
$ fg_percent   <dbl> 0.630, 0.500, 0.500, 0.462, 0.563, 0.647, 0.429, 0.545, 0…
$ p3fg         <dbl> 2, 5, 1, 1, 1, 2, 3, 4, 3, 0, 3, 0, 5, 2, 0, 1, 2, 3, 1, …
$ p3fga        <dbl> 10, 8, 2, 9, 5, 5, 9, 6, 8, 4, 6, 7, 10, 6, 1, 3, 6, 6, 3…
$ p3fg_percent <dbl> 0.200, 0.625, 0.500, 0.111, 0.200, 0.400, 0.333, 0.667, 0…
$ ft           <dbl> 7, 10, 16, 10, 7, 4, 8, 1, 1, 5, 1, 2, 0, 0, 2, 1, 0, 0, …
$ fta          <dbl> 10, 11, 16, 14, 10, 4, 8, 2, 2, 6, 1, 2, 0, 0, 2, 3, 0, 0…
$ ft_percent   <dbl> 0.700, 0.909, 1.000, 0.714, 0.700, 1.000, 1.000, 0.500, 0…
$ orb          <dbl> 0, 4, 2, 0, 1, 2, 0, 3, 1, 0, 1, 2, 0, 3, 5, 1, 0, 0, 1, …
$ drb          <dbl> 12, 7, 3, 5, 4, 5, 1, 6, 6, 9, 1, 2, 1, 2, 3, 6, 2, 4, 1,…
$ trb          <dbl> 12, 11, 5, 5, 5, 7, 1, 9, 7, 9, 2, 4, 1, 5, 8, 7, 2, 4, 2…
$ ast          <dbl> 9, 7, 4, 5, 9, 2, 4, 6, 5, 3, 2, 5, 0, 0, 5, 9, 3, 3, 1, …
$ stl          <dbl> 2, 2, 1, 2, 2, 0, 3, 1, 4, 0, 0, 1, 1, 1, 2, 1, 2, 0, 0, …
$ blk          <dbl> 1, 1, 0, 2, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 2, 1, 0, 1, …
$ tov          <dbl> 3, 4, 1, 3, 5, 3, 2, 2, 2, 4, 0, 4, 2, 0, 1, 4, 0, 1, 0, …
$ pf           <dbl> 1, 5, 4, 2, 5, 6, 3, 3, 3, 6, 2, 3, 0, 4, 6, 5, 2, 2, 2, …
$ pts          <dbl> 43, 39, 31, 35, 26, 28, 23, 17, 14, 23, 16, 18, 17, 16, 6…
$ plus_minus   <dbl> -8, 9, 20, 3, -14, -1, 1, 4, 8, 0, 2, -11, 5, 2, 9, 20, -…
$ gm_sc        <dbl> 38.9, 33.1, 27.5, 24.6, 20.4, 19.4, 19.2, 17.2, 15.4, 13.…
$ date         <date> 2025-10-21, 2025-10-21, 2025-10-21, 2025-10-21, 2025-10-…

3.4 Kontrola konzistencie

Zobraziť kód
data.frame(
  kontrola = c("úplne zhodné riadky",
               "úspešné strely > pokusené (fg > fga)",
               "úspešné trojky > pokusené (p3fg > p3fga)",
               "úspešné trestné hody > pokusené (ft > fta)",
               "doskoky spolu != ofenzívne + defenzívne"),
  pocet = c(sum(duplicated(udaje)),
            sum(udaje$fg   > udaje$fga),
            sum(udaje$p3fg > udaje$p3fga),
            sum(udaje$ft   > udaje$fta),
            sum(udaje$trb != udaje$orb + udaje$drb))
) %>%
  kable(col.names = c("Kontrola", "Počet nezrovnalostí")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2")
Kontrola Počet nezrovnalostí
úplne zhodné riadky 0
úspešné strely > pokusené (fg > fga) 0
úspešné trojky > pokusené (p3fg > p3fga) 0
úspešné trestné hody > pokusené (ft > fta) 0
doskoky spolu != ofenzívne + defenzívne 0
TipZáver: údaje sú konzistentné

Duplicity ani logické nezrovnalosti sa v údajoch nenachádzajú. Záporné hodnoty v plus_minus a gm_sc sú správne, tieto ukazovatele môžu byť záporné. Odľahlé hodnoty (napr. 83 bodov v jednom zápase) sú skutočné výnimočné výkony, nie chyby, preto ich ponechám.

Zobraziť kód
write.csv2(udaje, "nba_cista.csv", row.names = FALSE, fileEncoding = "UTF-8")

4 Základný prehľad čistých údajov

Zobraziť kód
cat("Obdobie:", format(min(udaje$date)), "až", format(max(udaje$date)), "\n")
Obdobie: 2025-10-21 až 2026-06-13 
Zobraziť kód
cat("Počet hráčov:", n_distinct(udaje$player), "| Počet tímov:", n_distinct(udaje$tm), "\n")
Počet hráčov: 582 | Počet tímov: 30 
Zobraziť kód
udaje %>%
  select(mp, pts, trb, ast, p3fg, plus_minus, gm_sc) %>%
  summary()
       mp             pts            trb              ast        
 Min.   : 0.00   Min.   : 0.0   Min.   : 0.000   Min.   : 0.000  
 1st Qu.:14.80   1st Qu.: 4.0   1st Qu.: 1.000   1st Qu.: 1.000  
 Median :23.30   Median : 9.0   Median : 3.000   Median : 2.000  
 Mean   :22.22   Mean   :10.6   Mean   : 4.022   Mean   : 2.441  
 3rd Qu.:30.47   3rd Qu.:16.0   3rd Qu.: 6.000   3rd Qu.: 4.000  
 Max.   :52.30   Max.   :83.0   Max.   :25.000   Max.   :23.000  
                                                                 
      p3fg          plus_minus      gm_sc        
 Min.   : 0.000   Min.   :-60   Min.   :-10.200  
 1st Qu.: 0.000   1st Qu.: -7   1st Qu.:  2.500  
 Median : 1.000   Median :  0   Median :  7.300  
 Mean   : 1.217   Mean   :  0   Mean   :  8.635  
 3rd Qu.: 2.000   3rd Qu.:  7   3rd Qu.: 13.300  
 Max.   :12.000   Max.   : 52   Max.   : 60.500  
                  NA's   :30                     

5 Ukážka časového radu

Pre kontrolu, že údaje sú naozaj usporiadané v čase, zobrazím priemerný počet bodov na hráča podľa dňa (zahrnuté sú len výkony s aspoň 10 odohranými minútami, aby sa nezapočítavali hráči s epizódnou rolou).

Zobraziť kód
denne <- udaje %>%
  filter(mp >= 10) %>%
  group_by(date) %>%
  summarise(priemer_bodov = mean(pts), pocet_vykonov = n(), .groups = "drop")

ggplot(denne, aes(x = date, y = priemer_bodov)) +
  geom_line(color = "#1d428a", alpha = 0.45, linewidth = 0.6) +
  geom_smooth(method = "loess", formula = y ~ x, se = FALSE,
              color = "#c8102e", linewidth = 1.3) +
  scale_x_date(date_breaks = "1 month", date_labels = "%m/%Y") +
  theme_minimal(base_size = 13) +
  theme(
    plot.title       = element_text(face = "bold", color = "#1d428a"),
    plot.subtitle    = element_text(color = "grey40"),
    panel.grid.minor = element_blank(),
    axis.title       = element_text(color = "grey30")
  ) +
  labs(title = "Priemerný počet bodov na hráča počas sezóny 2025/26",
       subtitle = "Modrá: denný priemer, červená: vyhladený trend",
       x = "Dátum", y = "Priemer bodov")

Červená čiara zobrazuje vyhladený trend. Jednotlivé dni sa líšia hlavne počtom odohraných zápasov, preto ďalej uvádzam aj mesačný prehľad:

Zobraziť kód
udaje %>%
  filter(mp >= 10) %>%
  mutate(mesiac = floor_date(date, "month")) %>%
  group_by(mesiac) %>%
  summarise(
    vykony     = n(),
    body       = mean(pts),
    trojky     = mean(p3fg),
    game_score = mean(gm_sc),
    .groups = "drop"
  ) %>%
  kable(digits = 2,
        col.names = c("Mesiac", "Počet výkonov", "Priemer bodov",
                      "Priemer úspešných trojok", "Priemer Game Score"),
        caption = "Mesačné priemery (hráči s aspoň 10 minútami)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2")
Mesačné priemery (hráči s aspoň 10 minútami)
Mesiac Počet výkonov Priemer bodov Priemer úspešných trojok Priemer Game Score
2025-10-01 1466 12.50 1.42 10.01
2025-11-01 4011 12.43 1.42 10.12
2025-12-01 3637 12.46 1.42 10.20
2026-01-01 4301 12.03 1.39 9.88
2026-02-01 3083 12.02 1.40 9.90
2026-03-01 4425 12.20 1.40 10.03
2026-04-01 2537 12.64 1.45 10.33
2026-05-01 636 12.42 1.37 9.83
2026-06-01 80 12.60 1.57 9.64

6 Zdroj údajov

NBA Player Stats – Season 25/26, Kaggle Datasets: https://www.kaggle.com/datasets. Súbor: nba_dailyleaders_full.csv.