5.7 Poznámka k doplňování hodnot do tabulek

Stejně jako v případě ostatních základních datových struktur v R, je i v případě tabulek možné přiřadit novou hodnotu do výběru. To se hodí např. v situaci, kdy potřebujete nějakou hodnotu opravit nebo aktualizovat. Často se také hodí ukládat vypočtené nebo stahované hodnoty do tabulky. V tomto posledním případě je však potřeba jisté opatrnosti, protože ukládání do výběru tabulky je výpočetně extrémně nákladná operace (kvůli nákladům na vyhledání dané hodnoty). V případě malých tabulek to není problém, v případě tabulek o milionech řádků to už však může být problematické. Ukažme si to na příkladu (nenechte se vyvést z míry tím, že nebudete rozumět všem detailům; většině porozumíte později v tomto textu).

Nejdříve vytvoříme dva vektory o délce 10 milionů hodnot, první celočíselný a druhý reálný. Vektory naplníme chybějícími hodnotami NA. Vytvoříme i dvě tabulky, které naplníme těmito vektory. První tabulka bude třídy data.frame, druhá třídy tibble. Náš test spočívá v tom, že do každého vektoru budeme chtít vložit na stejnou pozici jedničku. Funkce microbenchmark() ze stejnojmenného balíku nám změří, jak dlouho bude tato operace trvat.

library(microbenchmark)
library(dplyr)
library(tibble)

x <- rep(NA_integer_, 1e7)
y <- rep(NA_real_, 1e7)
df <- data.frame(x = x, y = y)
dt <- tibble(x = x, y = y)

performance <- microbenchmark("vektory" = {x[1000] <- 1L; y[1000] <- 1},
                              "data.frame 1" = {df[1000, "x"] <- 1L; df[1000, "y"] <- 1},
                              "data.frame 2" = {df$x[1000] <- 1L; df$y[1000] <- 1},
                              "data.frame 3" = df[1000, ] <- data.frame(x = 1L, y = 1),
                              "tibble 1" = {dt[1000, "x"] <- 1L; dt[1000, "y"] <- 1},
                              "tibble 2" = {dt$x[1000] <- 1L; dt$y[1000] <- 1},
                              "tibble 3" = dt[1000, ] <- tibble(x = 1L, y = 1),
                              unit = "ms") %>% 
    summary() %>% select(expr, min, mean, median, max)
Tabulka 5.2: Čas potřebný na vložení dvou hodnot do vektorů a tabulek v milisekundách.
expr min mean median max
vektory 0.001329 0.7941644 0.007186 74.59567
data.frame 1 62.955738 76.4914530 69.643374 124.38591
data.frame 2 43.684080 71.7981271 68.445594 138.33817
data.frame 3 64.195109 81.9319805 71.961323 174.75257
tibble 1 128.990932 151.7516711 142.678711 214.45897
tibble 2 63.691950 78.2379830 70.619257 129.24491
tibble 3 127.399926 157.8523898 143.193050 251.32895

Vysledky jsou dramaticke, jak ukazuje tabulka 5.2. Vložení dvou hodnot do tabulek trvá (na mém poměrně výkonném počítači) v průměru několik desítek milisekund, zatímco vložení do vektoru trvá na stejném počítači tisíciny milisekund (pokud se díváme na mediány). Praktický výsledek je zřejmý: pokud vkládáte do tabulky jednotlivé hodnoty, nevadí to, pokud je tabulka malá nebo vkládáte jen velmi málo hodnot. V opačném případě se výrazně vyplatí pracovat s vektory. Jednou jsem potřeboval zjistit vzdálenosti vzdušnou čarou mezi asi 5 000 čerpacími stanicemi. Bylo tedy potřeba spočítat a uložit asi 12 milionů vzdáleností (vzdálenost vzdušnou čarou je symetrická). Vlastní výpočet vzdálenosti je extrémně rychlý. Přesto však celý výpočet neskončil ani za čtyři dny – spočítalo se asi jen 1.5 milionu hodnot. Na vině bylo to, že jsem doplňoval hodnoty přímo do tabulky. Když jsem kód přepsal tak, aby pracoval s vektory, které jsem spojil do tabulky až nakonec, výpočet proběhl zhruba za půl hodiny.

Všimněte si také toho, že jsem vektory a tabulky celé předalokoval. Kdybychom chtěli datové struktury zvětšovat postupně přidáváním dalších a dalších hodnot nebo řádků, byl by výpočet ještě pomalejší, protože by R muselo neustále alokovat nové bloky paměti a do nich nejdříve překopírovat stará data, a teprve potom přidat nové hodnoty. To by se opakovalo při každém zvětšení vektoru nebo tabulky.

Pokud se chcete dozvedet vic o efektivnosti kodu v R, doporucuji zejmena Wickham (2014), kap. Performance a Profiling. Uzitecne je take Burns (2011).

References

Burns, Patrick. 2011. "The R Inferno." http://www.burns-stat.com/pages/Tutor/R_inferno.pdf.

Wickham, Hadley. 2014. Advanced R. 1st ed. Boca Raton, Florida, USA: Chapman; Hall/CRC. http://adv-r.had.co.nz/.