11.1 Textové tabulární delimitované soubory

Základní způsob výměny dat jsou textové tabulární delimitované formáty, kde jednotlivé řádky odpovídají pozorováním a kde jsou sloupce (proměnné) odděleny nějakým jasně definovaným znakem, např. mezerou, čárkou, středníkem nebo dvojtečkou. Velká výhoda těchto formátů je, že je možné je načíst téměř do každého softwaru, který pracuje s daty a stejně tak je z něj i vypsat. Zároveň jsou data “čitelná lidmi” a pokud se něco pokazí, je často možné data nějak zachránit. Nevýhodou je, že tyto formáty mohou obsahovat pouze tabulární data (tabulky), nemohou obsahovat metadata (např. atributy), jejich načítání může trvat dlouho (pokud jsou data velká) a že data v těchto formátech na disku zabírají hodně místa (pokud nejsou komprimovaná).

Příkladem dat v textovém tabulárním formátu je např. soubor “bmi_data.csv”. Na disku vypadá takto:

id,height,weight,bmi
1,153,55,23.4952368747
2,207,97,22.6376344839
3,173,83,27.7322997761
4,181,92,28.0821708739
5,164,112,41.6418798334

Zde se podíváme na to, jak data v textovém tabulárním formátu načíst a uložit pomocí funkcí z balíku readr. Oproti podobným funkcím ze základního R, tyto funkce načítají data rychleji, umožňují přesněji určit, jak se mají data načíst a neprovádí některé nepříjemné úpravy. Před použitím těchto funkcí musíme nejdříve načíst balík readr:

library(readr)

11.1.1 Načítání dat

Všechny funkce z balíku readr, které sloužící k načítání dat, jsou pojmenované read_XXX(), kde XXX je jméno načítaného formátu. Data ve formátu CSV tedy načítá funkce read_csv(). (Pozor! Funkce ze základního R určené k načtení těchto dat jsou pojmenované téměř stejně, jen místo podtržítka je jméno formátu oddělené tečkou. Obdobou funkce read_csv() je funkce read.csv() ze základního balíku. Přestože se funkce jmenují podobně, mají výrazně odlišný interface i chování.) Všechny funkce read_XXX() z balíku readr vracejí tabulku třídy tibble.

Základní funkcí k načtení textových delimitovaných tabulárních dat je funkce read_delim(). Při jejím použití je potřeba zadat zejména dva parametry: jméno načítaného souboru včetně cesty a v parametru delim znak, který odděluje jednotlivé proměnné v datech. V našem případě nastavíme delim = ",":

bmi_data <- read_delim("data/reading_and_writing/bmi_data.csv", delim = ",")
## Parsed with column specification:
## cols(
##   id = col_double(),
##   height = col_double(),
##   weight = col_double(),
##   bmi = col_double()
## )
bmi_data
## # A tibble: 5 x 4
##      id height weight   bmi
##   <dbl>  <dbl>  <dbl> <dbl>
## 1     1    153     55  23.5
## 2     2    207     97  22.6
## 3     3    173     83  27.7
## 4     4    181     92  28.1
## 5     5    164    112  41.6

Textová tabulární data mohou mít jednotlivé proměnné oddělené různě. Existují však tři nejobvyklejší varianty, pro které má readr speciální varianty funkce read_delim():

  • read_csv() načítá klasický americký standard CSV, kde jsou jednotlivé proměnné oddělené čárkami a celou a desetinnou část čísla odděluje desetinná tečka,
  • read_csv2() načítá “evropskou” variantu CSV, kde jsou jednotlivé proměnné oddělené středníky a desetinná místa v číslech odděluje čárka a
  • read_tsv() načítá variantu formátu, kde jsou proměnné oddělené tabelátorem.

V těchto funkcích není potřeba nastavovat parametr delim; většinu ostatních parametrů mají tyto funkce stejné jako funkce read_delim().

Protože dataset “bmi_data.csv” splňuje klasický formát CSV, můžeme jej pohodlněji načíst i pomocí funkce read_csv():

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv")
## Parsed with column specification:
## cols(
##   id = col_double(),
##   height = col_double(),
##   weight = col_double(),
##   bmi = col_double()
## )

Všechny funkce read_XXX() berou první řádek datového souboru implicitně jako jména proměnných. Pokud soubor jména proměnných neobsahuje, je to třeba funkcím říct pomocí parametru col_names. Ten může nabývat jedné ze tří hodnot. Pokud má hodnotu TRUE, pak první řádek souboru chápe jako jména proměnných. Pokud má hodnotu FALSE, pak se předpokládá, že první řádek souboru jména proměnných neobsahuje; z řádku se načtou data a funkce sama jednotlivé proměnné pojmenuje X1, X2 atd. Třetí možností je zadat jména proměnných ručně. V tomto případě musí být parametr col_names zadán jako vektor řetězců, který obsahuje jména jednotlivých proměnných. Na rozdíl od funkcí ze základního R, funkce z balíku readr jména proměnných nijak nemodifikují. V důsledku toho nemusejí být jména proměnných platnými názvy proměnných v R. To je však vždy možné opravit pomocí funkce names() nebo setNames().

Ukážeme si to na příkladu. Soubor “bmi_data_headless.csv” obsahuje stejná data jako soubor “bmi_data.csv”, na prvním řádku však nejsou uvedena jména sloupců, ale dataset začíná přímo daty. Pokud bychom dataset načetli stejně jako výše, funkce read_csv() by první řádek použila k pojmenování proměnných (jména sloupců by navíc v našem případě byla syntakticky nepřípustná, takže bychom je museli používat spolu se zpětnými apostrofy):

read_csv("data/reading_and_writing/bmi_data_headless.csv")
## Parsed with column specification:
## cols(
##   `1` = col_double(),
##   `153` = col_double(),
##   `55` = col_double(),
##   `23.4952368747` = col_double()
## )
## # A tibble: 4 x 4
##     `1` `153`  `55` `23.4952368747`
##   <dbl> <dbl> <dbl>           <dbl>
## 1     2   207    97            22.6
## 2     3   173    83            27.7
## 3     4   181    92            28.1
## 4     5   164   112            41.6

Tomu můžeme zabránit tak, že nastavíme parametr col_names = FALSE, takže se první řádek souboru považuje za data:

read_csv("data/reading_and_writing/bmi_data_headless.csv",
         col_names = FALSE)
## Parsed with column specification:
## cols(
##   X1 = col_double(),
##   X2 = col_double(),
##   X3 = col_double(),
##   X4 = col_double()
## )
## # A tibble: 5 x 4
##      X1    X2    X3    X4
##   <dbl> <dbl> <dbl> <dbl>
## 1     1   153    55  23.5
## 2     2   207    97  22.6
## 3     3   173    83  27.7
## 4     4   181    92  28.1
## 5     5   164   112  41.6

Nebo tak, že pomocí tohoto parametru přímo zadáme jména jednotlivých sloupců, např. jako col_names = c("id", "výška", "váha", "bmi") (první řádek souboru se bude opět považovat za data):

read_csv("data/reading_and_writing/bmi_data_headless.csv",
         col_names = c("id", "výška", "váha", "bmi"))
## Parsed with column specification:
## cols(
##   id = col_double(),
##   výška = col_double(),
##   váha = col_double(),
##   bmi = col_double()
## )
## # A tibble: 5 x 4
##      id výška  váha   bmi
##   <dbl> <dbl> <dbl> <dbl>
## 1     1   153    55  23.5
## 2     2   207    97  22.6
## 3     3   173    83  27.7
## 4     4   181    92  28.1
## 5     5   164   112  41.6

Některé datové soubory obsahují v prvních řádcích nějaké balastní informace, např. údaje o pořízení dat, copyrightu, parametrech simulace apod. Tyto řádky je možné přeskočit pomocí parametru skip: např. skip = 5 znamená, že se má přeskočit prvních pět řádků. Podobně některé soubory obsahují mezi skutečnými daty komentáře. Pokud jsou tyto komentáře uvozeny nějakým jasným znakem, můžeme je při načítání dat přeskočit pomocí parametru comment: např. comment = "#" znamená, že se přeskočí všechny řádky, které začínají “křížkem”.

Opět si to ukážeme na příkladu. Soubor “bmi_data_comments.csv” opět obsahuje stejná data jako “bmi_data.csv”, na prvních dvou řádcích však obsahuje nějaké informace o experimentu. Na disku vypadá soubor takto:

Experiment no. 747.
Top secret
id,height,weight,bmi
1,153,55,23.4952368747
2,207,97,22.6376344839
3,173,83,27.7322997761
4,181,92,28.0821708739
5,164,112,41.6418798334

Tento soubor musíme načíst s pomocí parametru skip; v opačném případě se věci opravdu pokazí (vyzkoušejte si to):

read_csv("data/reading_and_writing/bmi_data_comments.csv", skip = 2)
## Parsed with column specification:
## cols(
##   id = col_double(),
##   height = col_double(),
##   weight = col_double(),
##   bmi = col_double()
## )
## # A tibble: 5 x 4
##      id height weight   bmi
##   <dbl>  <dbl>  <dbl> <dbl>
## 1     1    153     55  23.5
## 2     2    207     97  22.6
## 3     3    173     83  27.7
## 4     4    181     92  28.1
## 5     5    164    112  41.6

Soubor “bmi_data_comments2.csv” obsahuje opět stejná data; nyní jsou však dvě množiny pozorování nadepsány komentáři a jeden řádek má také vlastní komentář:

id,height,weight,bmi
# the first set of observations
1,153,55,23.4952368747
2,207,97,22.6376344839
3,173,83,27.7322997761  # suspicious
# the second set of observations
4,181,92,28.0821708739
5,164,112,41.6418798334

V tomto případě musíme zadat znak, kterým začínají komentáře, pomocí parametru comment. Funkce read_XXX() pak ignorují vše od tohoto znaku do konce řádku:

read_csv("data/reading_and_writing/bmi_data_comments2.csv", comment = "#")
## Parsed with column specification:
## cols(
##   id = col_double(),
##   height = col_double(),
##   weight = col_double(),
##   bmi = col_double()
## )
## # A tibble: 5 x 4
##      id height weight   bmi
##   <dbl>  <dbl>  <dbl> <dbl>
## 1     1    153     55  23.5
## 2     2    207     97  22.6
## 3     3    173     83  27.7
## 4     4    181     92  28.1
## 5     5    164    112  41.6

Různé datové soubory kódují chybějící hodnoty různě. Standardně funkce read_XXX() očekávají, že chybějící hodnota je buď prázdná, nebo obsahuje řetězec “NA”. To je však možné změnit parametrem na. Do něj uložíte vektor všech hodnot, které má funkce read_XXX() považovat za NA. Pokud např. váš datový soubor kóduje chybějící hodnoty pomocí tečky, nastavíte na = ".". Pokud navíc může být zadaná chybějící hodnota i jako prázdný řetězec nebo řetězec “NA”, zadáte na = c("", ".", "NA"). (Funkce read_XXX() při načítání jednotlivých hodnot implicitně odstraní všechny úvodní a koncové mezery, takže našemu “tečkovému” pravidlu vyhoví jak řetězce “.”, tak i " . ". Toto chování můžete změnit parametrem trim_ws.) Následující kód ukazuje příklad:

read_csv("data/reading_and_writing/bmi_data_na.csv", na = c("", ".", "NA"))
## Parsed with column specification:
## cols(
##   id = col_double(),
##   height = col_double(),
##   weight = col_double(),
##   bmi = col_double()
## )
## # A tibble: 5 x 4
##      id height weight   bmi
##   <dbl>  <dbl>  <dbl> <dbl>
## 1     1    153     55  23.5
## 2     2    207     97  22.6
## 3     3     NA     83  27.7
## 4     4    181     NA  28.1
## 5     5    164    112  41.6

Jak jste si asi všimli, funkce read_XXX() při načítání dat samy odhadnou, jaká data obsahují jednotlivé proměnné, a převedou je na daný datový typ. (Výsledná tabulka třídy tibble tyto typy vypisuje pod jmény proměnných.) Informace o tom, jaký typ funkce zvolila pro který sloupec, se vypíše při načítání: informace začíná “Parsed with column specification: cols(…”, viz výše. V našem případě se např. první tři proměnné převedly na celá čísla, zatímco poslední proměnná na reálné číslo. Funkce read_XXX() odhadují typ proměnné na základě prvních 1 000 načtených řádků (toto číslo je možné změnit pomocí parametru guess_max). Nechat si datový typ odhadnout, je pohodlné, ale nepříliš bezpečné. Mnohem rozumnější je zadat datový typ jednotlivých sloupců ručně pomocí parametru col_types. Ten je mozne zadat tremi zpusoby. Zaprve, hodnota NULL indikuje, ze se typy promennych maji odhadnout. Zadruhe, datove typy jednotlivych sloupcu je mozne zadat plnymi jmeny ve funkci cols(). A zatreti, tato jmena muzeme zkratit do jednopismennych zkratek zadanych v jednom retezci. Seznam typu sloupcu a jejich zkratek uvadi tabulka 11.1. Rozdíl mezi funkcemi col_double() a col_number() spočívá v tom, že col_number() umožňuje mít před a za vlastním číslem nějaké nečíselné znaky, které zahodí. To se hodí např. při načítání peněžních údajů, kde col_number() zvládne převést na číslo i řetězce jako $15.30 nebo 753 Kč.

Tabulka 11.1: Seznam jmen funkcí pro určení datového typu načítané proměnné.
funkce význam zkratka parametry
col_logical() logická proměnná “l”
col_integer() striktní celé číslo “i”
col_double() striktní reálné číslo “d”
col_number() flexibilní číslo “n”
col_character() řetězec “c”
col_date() datum (jen den bez hodin) “D” format
col_datetime() datum (den i hodina) “T” format
col_time() čas (jen hodiny, minuty a sekundy) “t” format
col_factor() faktor levels, ordered, include_na
col_guess() typ odhadne R “?”
col_skip() proměnná se přeskočí a nenačte "_" nebo “-”

Přesně stejného výsledku, jakého v našem případě dosáhlo automatické rozpoznávání typů sloupců, můžeme dosáhnout manuálně takto (v tomto případě R nevypíše informaci o sloupcích):

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv",
                     col_types = cols(id = col_integer(),
                                      height = col_integer(),
                                      weight = col_integer(),
                                      bmi = col_double()))

nebo stručněji takto:

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv",
                     col_types = "iiid")

Specifikací sloupců můžeme samozřejmě změnit i typ sloupců. Někdy např. můžeme chtít načíst všechny proměnné jako řetězce, a pak si je zkonvertovat sami. To můžeme udělat třemi způsoby: 1) sloupce můžeme nastavit pomocí plného volání funkcí col_types = cols(id = col_character(), height = col_character(), weight = col_character(), bmi = col_character()), 2) je můžeme nastavit pomocí zkratkových písmen jako col_types = "cccc" nebo 3) nastavíme implicitní typ sloupce pomocí speciálního parametry .default buď plným voláním funkce col_types = cols(.default = col_character()) nebo pomocí zkratkového písmene:

read_csv("data/reading_and_writing/bmi_data.csv",
         col_types = cols(.default = "c"))
## # A tibble: 5 x 4
##   id    height weight bmi          
##   <chr> <chr>  <chr>  <chr>        
## 1 1     153    55     23.4952368747
## 2 2     207    97     22.6376344839
## 3 3     173    83     27.7322997761
## 4 4     181    92     28.0821708739
## 5 5     164    112    41.6418798334

Nejjednodušší způsob, jak explicitně zadat datové typy sloupců tabulky, je nechat funkci read_XXX() odhadnout datový typ sloupců, a pak specifikaci cols() zkopírovat a případně upravit. Po vlastním načtení je možné specifikaci získat i pomocí funkce spec(), jejímž jediným argumentem je načtená tabulka. Specifikaci je možné zjednodušit pomocí funkce cols_condense(), která nejčastěji používaný datový typ shrne do parametru .default:

cols_condense(spec(bmi_data))
## cols(
##   .default = col_integer(),
##   bmi = col_double()
## )

Nektere funkce col_XXX umoznuji zadat parametry. Funkce pro nacitani data a casu umoznuji zadat format, ve kterem je datum nebo cas ulozen. Funkce pro nacitani faktoru umoznuji zadat platne urovne faktoru, to, zda je faktor ordinalni, a to, zda ma byt hodnota NA soucasti urovni faktoru. Uplny seznam parametru uvadi tabulka 11.1. Pokud bychom např. chtěli načíst proměnnou id jako faktor se třemi úrovněmi (“1”, “2” a “3”), můžeme to udělat takto (funkce read_XXX() nikdy nic nepřevádí na faktory sami od sebe – pokud chcete proměnnou převést na faktor, musíte o to požádat):

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv",
                     col_types = cols(id = col_factor(levels = as.character(1:3)),
                                      height = col_integer(),
                                      weight = col_integer(),
                                      bmi = col_double()))
## Warning: 2 parsing failures.
## row col           expected actual                                    file
##   4  id value in level set      4 'data/reading_and_writing/bmi_data.csv'
##   5  id value in level set      5 'data/reading_and_writing/bmi_data.csv'

Funkce vypíše varování, protože proměnná id obsahuje i jiné než povolené úrovně, a nepovolené úrovně nahradí hodnotami NA. (Pokud bychom chtěli nechat funkci read_XXX() odhadnout úrovně faktoru z dat, museli bychom zadat parametr levels = NULL.)

Funkcím read_XXX() je možné sdělit i to, které proměnné z tabulky vyloučit. K tomu slouží funkce col_skip(). Řekněme, že bychom chtěli náši tabulku anonymizovat tím, že z dat odstraníme identifikátory id. Toho můžeme dosáhnout např. takto:

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv",
                     col_types = cols(id = col_skip(),
                                      height = col_integer(),
                                      weight = col_integer(),
                                      bmi = col_double()))
bmi_data
## # A tibble: 5 x 3
##   height weight   bmi
##    <int>  <int> <dbl>
## 1    153     55  23.5
## 2    207     97  22.6
## 3    173     83  27.7
## 4    181     92  28.1
## 5    164    112  41.6

Pokud bychom chtěli načíst jen některé proměnné, stačí nahradit funkci cols() funkcí cols_only() a v ní uvést pouze proměnné, které se mají načíst. Následující kód načte pouze proměnné height a bmi:

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv",
                     col_types = cols_only(height = col_integer(),
                                           bmi = col_double()))
bmi_data
## # A tibble: 5 x 2
##   height   bmi
##    <int> <dbl>
## 1    153  23.5
## 2    207  22.6
## 3    173  27.7
## 4    181  28.1
## 5    164  41.6

Jak jsme viděli výše, pokud se při načítání jednotlivých sloupců tabulky něco pokazí, funkce read_XXX() o tom vypíší varování a příslušnou “buňku” tabulky doplní hodnotou NA. K tomu může dojít z různých důvodů: Datový typ, který jste zadali (nebo který R odhadlo na základě prvních 1 000 řádků) není dost obecný pro všechny řádky tabulky. První řádky např. obsahují jen celá čísla, zatímco pozdější řádky i reálná čísla. Faktor obsahuje i jiné hodnoty, než zadané platné úrovně atd. Pokud je varování hodně, zobrazí se jen několik prvních varování. Všechna varování je možné vypsat funkcí problems(), jejímž jediným argumentem je načtená tabulka.

Většinou je moudré ladit zadání typů sloupců ve specifikaci cols() tak dlouho, až R nevypisuje žádná varování. To je užitečné zejména v případě, že načítáte různé datové soubory se stejnou strukturou. Když se potom u některého souboru objeví varování, znamená to, že se v datech něco změnilo. Pokud chcete být opravdu důkladně varováni, že k tomu došlo, můžete použít funkci stop_for_problems(). Jejím jediným argumentem je načtená tabulka. Pokud při jeho načtení došlo k nějakým varováním, funkce stop_for_problems() zastaví běh skriptu.

Tabularni datove soubory jsou obycejne textove soubory bez specialniho formatovani. Proto cela rada prvku techto souboru neni standardizovana. Jednotlive datove soubory se mohou lisit kodovanim, znakem pouzitym pro oddeleni celych a desetinnych cisel, znakem pouzitym pro oddeleni tisicu, jmeny mesicu a dnu v tydnu apod. Balik readr implicitne pouziva americkou konvenci: kodovani je UTF-8, desetinna mista oddeluje tecka, tisice carka a veskera jmena jsou anglicka. Toto chovani muzete zmenit pomoci parametru locale, do ktereho vlozite objekt vytvoreny funkci locale(). Jeji zakladni parametry uvadi tabulka 11.2.

Tabulka 11.2: Seznam jmen funkcí pro určení datového typu načítané proměnné.
parametr význam impl. hodnota
date_names řetězec pro jména datumů (česká “cs”, slovenská “sk”) “en”
date_format formát data “%AD”
time_format formát času “%AT”
decimal_mark znak pro oddělení desetinných míst “.”
grouping_mark znak pro oddělení tisíců “,”
tz časová zóna “UTC”
encoding kódování souboru “UTF-8”
asciify jestli soubor odstranil diakritiku ze jmen datumů FALSE

Nastavení ve funkci locale si můžete vyzkoušet tak, že je necháte vypsat do konzoly. Typické české nastavení data vytvořená z LibreOffice na Linuxu s formátem data typu 31. 12. 2017 by vypadalo takto:

locale("cs",
       date_format = "%d.%*%m.%*%Y",
       decimal_mark = ",", grouping_mark = ".",
       tz = "Europe/Prague")
## <locale>
## Numbers:  123.456,78
## Formats:  %d.%*%m.%*%Y / %AT
## Timezone: Europe/Prague
## Encoding: UTF-8
## <date_names>
## Days:   neděle (ne), pondělí (po), úterý (út), středa (st), čtvrtek (čt), pátek
##         (pá), sobota (so)
## Months: ledna (led), února (úno), března (bře), dubna (dub), května (kvě),
##         června (čvn), července (čvc), srpna (srp), září (zář), října
##         (říj), listopadu (lis), prosince (pro)
## AM/PM:  dopoledne/odpoledne

Složitější nastavení locale, např. jak nastavit jména dnů a měsíců v nepodporovaném jazyce nebo jak zjistit časovou zónu, najdete v příslušné vinětě balíku readr.

Největší oříšek je v našich končinách zjistit, jaké kódování má daný soubor. K tomu může pomoci funkce guess_encoding(), jejímž jediným parametrem je jméno souboru, jehož kódování chceme odhadnout. Funkce vypíše seznam několika kódování a u nich pravděpodobnost, kterou tomuto kódování přikládá. Pokud funkci vyzkoušíme na našem testovacím souboru, dostaneme následující výsledek:

guess_encoding("data/reading_and_writing/bmi_data.csv")
## # A tibble: 1 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 ASCII             1

Protože náš soubor neobsahuje žádnou diakritiku, je si funkce guess_encoding() zcela jistá, že se jedná o ASCII soubor. (Protože ASCII je podmnožinou UTF-8, nemusíme kódování explicitně deklarovat.)

11.1.2 Načtení tabulárních dat v RStudiu

Při interaktivní práci je možné využít toho, že RStudio umí načíst tabulární textová data. V záložce Environment klikněte na Import Dataset a zvolte From CSV. Nástroj odhadne většinu potřebných parametrů a zbytek (včetně locale) je možné konfigurovat. Příjemné je, že nástroj vygeneruje i potřebný kód, který můžete překopírovat do svého skriptu. Nástroj vám tedy umožní vizuálně odladit základní nastavení načítání dat, detaily můžete doladit později ve skriptu.

11.1.3 Načítání velkých souborů

Načítání velkých souborů funguje stejně jako načítání malých souborů – se dvěma specifiky: trvá déle a zabírá více operační paměti počítače. R dokáže pracovat pouze s proměnnými, které má v operační paměti. Pokud se pokusíte načíst data, která se do paměti počítače nevejdou, R spadne. Pokud tedy máte opravdu hodně velký datový soubor, je užitečné dopředu zjistit, kolik paměti zabere. To můžete udělat přibližně následujícím způsobem:

  1. zjistíte, kolik řádků má vaše tabulka (v Linuxu to můžete udělat pomocí prográmku wc),
  2. načtete prvních 1 000 řádků tabulky (počet řádků omezíte pomocí parametru n_max); přitom odladíte datové typy jednotlivých sloupců,
  3. zjistíte, kolik paměti tabulka zabírá pomocí funkce object.size() a
  4. vypočítáte, kolik paměti zabere celý datový soubor: vydělíte velikost vzorku dat tisícem a vynásobíte ji počtem řádků souboru.

Balík readr umožňuje do jisté míry omezení proměnných na operační paměť počítače obejít. K tomu slouží speciální funkce read_XXX_chunked() (ekvivalentem funkce read_delim() je funkce read_delim_chunked()). Tyto funkce čtou datový soubor po kusech. Nad každým kusem provedou nějakou agregační operaci (např. vyberou jen řádky, které splňují určitou podmínku, spočítají nějaké agregátní statistiky apod.) a do paměti ukládají jen výsledky těchto operací. Na detaily použití těchto funkcí se podívejte do jejich dokumentace.

Naštěstí pro vás, valná většina dat, se kterou budete v blízké budoucnosti pracovat, bude nejspíše tak malá, že nic z těchto triků nebudete muset používat. Například tabulka s milionem řádků a 20 sloupci, které všechny obsahují reálná čísla bude v paměti počítač zabírat 1 000  000 \(\times\) 20 \(\times\)\(=\) 160 000 000 bytů, tj. asi jen 153 MB.

11.1.4 Ukládání dat do textových tabulárních delimitovaných souborů

K zapsání dat do tabulárních formátů slouží funkce write_delim(), write_csv(), write_excel_csv() a write_tsv(). Prvním parametrem všech těchto funkcí je vždy tabulka, který se má zapsat na disk, druhým je cesta, kam se mají data zapsat. Dále je možné nastavit pomocí parametru na znak pro uložení hodnoty NA a určit, zda se mají data připsat na konec existujícího souboru. Funkce read_delim() umožňuje navíc nastavit pomocí parametru delim znak, který bude oddělovat jednotlivé sloupce tabulky. Funkce write_excel_csv() přidá do souboru kromě běžného CSV i znak, podle kterého MS Excel pozná, že soubor je v kódování UTF-8.

Tyto funkce bohužel neumožňují nastavit locale, takže výsledkem je vždy soubor v kódování UTF-8 s desetinnými místy oddělenými pomocí tečky, tisící oddělenými pomocí čárky atd. Pokud potřebujete něco jiného. podívejte se do dokumentace na odpovídající funkce ze základního R (tj. např. funkci write.csv()).

11.1.5 Spojení (connections)

Když R čte nebo zapisuje data, nepracuje přímo se soubory, ale se “spojeními” (connections). Spojení zobecňuje myšlenku souboru – spojení může být lokální soubor, soubor komprimovaný algoritmem gzip, bzip2 apod., URL a další.

Funkce read_XXX() vytvareji spojeni pro cteni dat automaticky. To znamena, ze jmeno souboru muze obsahovat jak lokalni soubor, tak URL. Internetovy odkaz funkce pozna podle uvodniho "http://", "https://", "ftp://” nebo “ftps://”. V takovém případě vzdálený soubor automaticky stáhne. Funkce umí číst i některý typy komprimovaných souborů. Ty pozná podle koncovky “.gz”, “.bz2”, .“xz” nebo “.zip”. Takový soubor funkce automaticky dekomprimuje.

Předpokládejme, že náš datový soubor je pro úsporu místa na disku komprimovaný pomocí programu gzip. Pak data načteme jednoduše takto:

bmi_data <- read_csv("data/reading_and_writing/bmi_data.csv.gz",
                     col_types = "iiid")
bmi_data
## # A tibble: 5 x 4
##      id height weight   bmi
##   <int>  <int>  <int> <dbl>
## 1     1    153     55  23.5
## 2     2    207     97  22.6
## 3     3    173     83  27.7
## 4     4    181     92  28.1
## 5     5    164    112  41.6

Podobně je možné načíst i data z internetu, stačí nahradit jméno souboru jeho URL:

country_codes <- read_csv(
    "http://www.correlatesofwar.org/data-sets/cow-country-codes/cow-country-codes",
    col_types = "cic")
head(country_codes)
## # A tibble: 6 x 3
##   StateAbb CCode StateNme                
##   <chr>    <int> <chr>                   
## 1 USA          2 United States of America
## 2 CAN         20 Canada                  
## 3 BHM         31 Bahamas                 
## 4 CUB         40 Cuba                    
## 5 CUB         40 Cuba                    
## 6 HAI         41 Haiti

Na rozdíl od funkcí ze základního R umí funkce write_XXX() i přímo zapisovat do komprimovaných souborů bez toho, aby bylo potřeba connection explicitně deklarovat (např. pomocí funkce gzfile()). Stačí uvést jméno souboru ukončené odpovídající koncovkou. Pokud tedy chceme uložit naši tabulku do komprimovaného souboru, můžeme to provést např. takto:

write_csv(bmi_data, "moje_data.csv.gz")

Vic detailu ke spojenim najdete napr. v (Spector 2008, s. 23-25) nebo (Peng 2016, s. 33–35).

References

Peng, Roger D. 2016. R Programming for Data Science. LeanPub. https://bookdown.org/rdpeng/rprogdatascience/.

Spector, Phil. 2008. Data Manipulation with R. 1st ed. Use R! Springer.