Struktury dat v R

Zpracovávání výzkumných dat pomocí jazyka R

Program

  • opakování z minulé hodiny
  • kontrola domácího úkolu
  • funkce v R
  • datové struktury v R
  • balíčky

Kontrola domácí práce

  1. vytvoření RProjektu

  2. nový R skript

  3. nahrání uložených dat

    load("promenne.RData")

    Jde nahrát RData soubor i jiným způsobem? Jaké jsou nevýhody tohoto přístupu?

  4. výpočet toho, kolik zaměstnanců s daným platem jde nabrat na specifikovanou dobu měsíců

    (rozpocet%/%plat)/pocetMesicu
    [1] 3
  5. A nešlo by to i jinak?

Funkce v R

Nedílnou součástí kódu v R jsou takzvané funkce. Jedná se o příkazy, které provedou specifickou akci za vámi definovaných podmínek.

název funkce(název argumentu = parametry argumentu)

Pomocí funkce seq vygeneruj sekvenci s rozestupem po 3 od 10 do 20.

seq(from = 10, to = 20, by = 3)
[1] 10 13 16 19

Co bude výsledkem následujícího kódu?

Lze psát příkazy i bez definování argumentů?

rep("ID", 5)
[1] "ID" "ID" "ID" "ID" "ID"

Ano; bez definování názvu argumentu se pracuje s jeho pořadím.

Je pořadí argumentů důležité? Ovlivní výsledek?

Pozor!

Na pořadí argumentu nezáleží, dokud jasně definujeme k jakému argumentu parametr patří.

Jaký bude výsledek těchto kódů? Jsou totožné?

Na doma

Rozdíl mezi = a <-

Možná jste se setkali s tím, že někdo zapisuje proměnné pomocí operátoru =. Funguje to?

x = 6
x + 1
[1] 7

Proč se proto místo toho používá <- ?

#definuj prvni argument a rovnou ho uloz jako promennou
rep(osobaID <- 5, 3)
[1] 5 5 5
osobaID + 4
[1] 9

R umožňuje provádět akce uvnitř “jiných akcí”

V tomto případě určujeme argument na první pozici, a zároveň jeho hodnotu ukládáme do proměnné osobaID.

Co bude výsledkem následujícího kódu?

Na jaké problémy zde narazíme?

  • osobaID_2 není argument funce rep

    • operátor = ve funkci neznamená přiřazení, ale určení argumentu

      • samotný argument osobaID_2 ve funkci rep neexistuje a proto nevznikne platný výsledek
  • nedošlo k zapsání do globálního prostředí a tuto neexistující proměnnou proto nelze používat

Samostatné cvičení

  1. Můžeme zapsat sekvenci od 1 do 10 s počtem hodnot 3 pomocí následujícího kódu? Pokud ne, opravte.

  2. Bez spuštění kódu určete, jaký bude výsledek této funkce. Používejte nápovědu, zkuste si jednotlivé části rozepsat.

    length(rep(seq(2, 10, 2), 3))

Řešení úlohy 1)

Můžeme zapsat sekvenci od 1 do 10 s počtem hodnot 3 pomocí následujícího kódu? Pokud ne, opravte.

Ne, jelikož argument na třetí pozici v této funkci není length.out, který určuje délku sekvence, ale by, který určuje periodu.

Čtěte dokumentaci pozorně!

R dokumentace je psana mnoha lidmi a nemusí být vždy konzistentní.

Správná podoba kódu by tedy byla

seq(from = 1, to = 10, length.out = 3)
[1]  1.0  5.5 10.0

Řešení úlohy 2)

Bez spuštění následujícího kódu určete, jaký bude výsledek této funkce. Používejte nápovědu, zkuste si jednotlivé části rozepsat.

Funkce length zjišťuje, jaká je “délka” objektu, jaký má počet hodnot. Potřebujeme proto spočítat, kolik hodnot nám vznikne jako výsledek funkce rep.

Funkce rep nám zde třikrát zopakuje výsledek daný funkcí seq.

Funkce seq(2, 10, 2) by zde mohla být zapsána na základě pořádí argumentů i jako seq(from = 2, to = 10, by = 2). Výsledkem je tak sekvence 2 4 6 8 10, která má pět čísel.

Třikrát se tedy zopakuje sekvence pěti čísel, což znamená že výsledek je patnáct.

Vnořování funkcí

Jak bylo vidět v přechozích částech, R umožňuje používat funkce uvnitř dalších funkcí.

Pro R je hlavně důležité, aby hodnoty v jednotlivých argumentech splňovaly jejich podmínky, nikoliv v jaké podobě tyto hodnoty do funkce vstupují.

trojka <- 3
rep(x = seq(1, 10, 3), times = trojka)
 [1]  1  4  7 10  1  4  7 10  1  4  7 10

V určité chvíli je ovšem dobré přemýšlet i o čitelnosti samotného kódu.

Který z následujících kódů je čitelnější?

sample(x = rep(x = seq(1, 10, 3), times = 2), size = 4, replace = FALSE)
[1]  1 10  7  1

nebo

opakovani <- rep(x = seq(1, 10, 3), times = 2)

sample(x = opakovani, size = 4, replace = FALSE)
[1] 1 1 7 4

Datové struktury v R

Vektor

série za sebou jdoucích hodnot totožného datového typu

  • vektor o jedné hodnotě je někdy nazýván skalár

  • jednodimenzionální (důležité hlavně při vyhledávání)

  • při použití více datových typů dochází k nucené konverzi do jednotného typu

seq(1, 10, 2)
[1] 1 3 5 7 9

Jakými jinými způsoby můžeme vektory vytvořit?

  • symbol : vytvoří sérii čísel v daných mezích

    • rozestup vždy po jedné
-5:3
[1] -5 -4 -3 -2 -1  0  1  2  3
0.65:9.18
[1] 0.65 1.65 2.65 3.65 4.65 5.65 6.65 7.65 8.65
  • funkce c spojí hodnoty jakéhokoliv typu do vektoru
c("jmeno", "prijmeni")
[1] "jmeno"    "prijmeni"
c(1, 5, 77)
[1]  1  5 77
  • způsobů je mnohem více, tyto se ale hodí znát

Potenciální zádrhely

Co se stane po projetí následujícího kódu?

Datový typ vektoru bude automaticky převeden na charakterový, jelikož vektor v sobě kombinuje několik datatypů dohromady.

Jaký bude datový typ následujícího vektoru?

vektorNA <- c(NA, 6, 9); vektorNA
[1] NA  6  9

NA označuje chybějící hodnotu, nikterak neurčuje samotný datový typ hodnoty.

Tip

Ke zjištění datového typu je možné použít funkci mode.

mode(vektorNA)
[1] "numeric"

Pojmenovávání hodnot

Jednotlivé hodnoty ve vektoru (ale i zbylých datových strukturách) je možné si pojmenovat.

jmena <- c(jan = 22, dan = 667, sam = 6)
names(jmena) #jake pojmenovani ma danna promenna?
[1] "jan" "dan" "sam"

Co znamená pojmenováná?

Při pojmenovávání připojujeme specifické hodnotě či sérii hodnot určitý štítek. Nejenomže popisuje vlastnost hodnot(y), kterou pojmenovává, ale zárověň ho lze použít i k vyhledávání (indexování) jednotlivých hodnot. Více o indexování si řekneme v následující hodině.

Pojmenování není to samé co přiřazování; nevytváříme nové objekty, pouze hodnotám přidáváme novou charakteristiku.

Co když si chci zpětně vektor pojmenovat?

vektorBezJmen <- c("Škoda", "Hyundai", "Vespa"); vektorBezJmen
[1] "Škoda"   "Hyundai" "Vespa"  
names(vektorBezJmen) #ma vektorBezJmen jmena?
NULL
names(vektorBezJmen) <- c("Česko", "Japonsko", "Itálie"); vektorBezJmen
    Česko  Japonsko    Itálie 
  "Škoda" "Hyundai"   "Vespa" 
names(vektorBezJmen)
[1] "Česko"    "Japonsko" "Itálie"  

Přiřazováním můžete měnit existující hodnoty

Přiřazování neslouží pouze k vytváření proměnných, může na nich provádět i změny. Nemusí se jednat pouze o celé proměnné (které jsou pouze pojmenováním určité hodnoty či jejich skupiny) ale i specifické hodnoty uvnitř nich či hodnoty je popisující.

Samostatné cvičení

  1. Vypište alespoň tři rozdílné způsoby, jak získat následující vektor:

  2. Vytvořte kód který upraví následující vektor tak, aby jména jednotlivých hodnot byla napsaná malými písmeny. Existuje pro toto i specifická funkce?

    id <- c(JMENO = "jan", PRIJMENI = "novak")
  3. Opravte následující kód tak, aby dával požadovaný výsledek; vektor s dvěmi hodnotami octavia se štítkem škoda.

Řešení úlohy 1)

Vypište alespoň tři rozdílné způsoby, jak získat následující vektor: 1 2 3 1 2 3 9 8 7 2

Řešení úlohy 2)

Vytvořte kód který upraví následující vektor tak, aby jména jednotlivých hodnot byla napsaná malými písmeny. Existuje pro toto i specifická funkce?

names(id) <- c("jmeno", "prijmeni")
id
   jmeno prijmeni 
   "jan"  "novak" 

Existuje funkce v base R tolower(). Co způsobí a jakým způsobem ji můžeme použít?

names(id) <- tolower(names(id))
id
   jmeno prijmeni 
   "jan"  "novak" 

Pokud nevíte, hledejte - spousta problémů a specifických use cases již byla dávno vyřešena a jsou k nalezení na internetu.

Řešení úlohy 3)

Opravte následující kód tak, aby dával požadovaný výsledek.

rep(škoda = "octavia", 2)
[1] 2

Nesmíte zapomenout, že symbol = uvnitř funkcí značí argument. Má funkce rep argument škoda?

Nic ovšem nebrání tomu opakovat vektor s již jednou pojmenovanou hodnotou:

rep(c(škoda = "octavia"), 2)
    škoda     škoda 
"octavia" "octavia" 

Faktor

způsob uchovávání kategoriálních dat

  • používají se hlavně během analýz a vizualizací, lze je ale využít i při kontrole správnosti dat

  • ukázka:

ukazkaFaktory <- as.factor(c("west", "north", "west", "south", "east", "north",
                             "south", "east", "north")); ukazkaFaktory
[1] west  north west  south east  north south east  north
Levels: east north south west
  • přestože vypadají jako charakterová data, ve skutečně se jedná o integery
str(ukazkaFaktory)
 Factor w/ 4 levels "east","north",..: 4 2 4 3 1 2 3 1 2

Jakým způsobem vzniká vektor?

abc <- as.factor(c("a", "b", "a", "c")); abc
[1] a b a c
Levels: a b c

R vytvoří kategorii z každé varianty a následně je seřadí v přehledu od nejnižší po největší.

str(abc)
 Factor w/ 3 levels "a","b","c": 1 2 1 3

Jednotlivé kategorie je taktéž možné zobrazit pomocí funkce levels.

levels(abc)
[1] "a" "b" "c"

Funkce as.x() dokáže měnit více data typů/struktur

Funkce as.x() dokážou měnit defacto všechny data typy/struktury:

as.character(1:4)
[1] "1" "2" "3" "4"
as.numeric("3")
[1] 3
as.logical("FALSE")
[1] FALSE

Pole (array)

objekt složený z vektorů stejného datového typu a délky v několika dimenzích1

  • jakým způsobem si představit dimenze?
    • Jedna dimenze: řada hodnot
    • Dvě dimenze: hodnoty v sloupcích a řádcích
    • Tři dimenze: dvě tabulky se sloupci a řádky naskládané za sebe
  • k vytvoření se používá primárně funkce array

Vektor

Pole o dvou dimenzích (matice)

Pole o třech dimenzích

  • use case
  • nejvíce nás ale bude zajímat datové pole o dvou dimenzích - matice

Matice (matrix)

dvojrozměrné pole

  • dvojrozměrný objekt znamená, že už se nejedná o objekt co má pouze jednu linii hodnot jako vektor, ale že má řádky a sloupce

    • defacto vektor ale poskládaný do řádků a sloupců místo toho aby byl natáhnutý

      • číslo v hranatých závorkách značí pozici hodnoty v dané dimenzi, více si k tomu ale řekneme v sekci indexování [Matice]
  • při pokusu o vytvoření matice z více datových typů dojde stejně jako u vektoru k nucené konverzi na charakter

Tvorba matice

Matici lze vytvořit pomocí mnoha funkcí. Pokud ji chceme vytvořit celou od začátku, můžeme použít funkcí matrix().

Jaký bude výsledek této funkce? Co znamenají jednotlivé argumenty?

  • data: hodnoty, které budou matici tvořit

  • nrow: počet řádků

  • ncol: počet sloupců

  • …a další

Jaký bude výsledek následující funkce?

Automatické generování hodnot

Při menším množství hodnot než je potřeba funkce matrix začne hodnoty opakovat. Pokud je více hodnot v data než je potřeba, dojde k erroru.

Co když ale chceme vytvořit matici z již existujících vektorů stejného typu a délky?

cbind() = spoj vektory po sloupcích (columns)

cbind(1:3, 5:7)
     [,1] [,2]
[1,]    1    5
[2,]    2    6
[3,]    3    7

rbind() = spoj vektory po řádcích (rows)

rbind(1:3, 5:7)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    5    6    7
  • Funkce matrix() taktéž umožňuje tvorbu matice po řádcích. Jak bychom toto provedli?
  • Argument byrow je automaticky nastaven na hodnotu FALSE. Pro seřazení po řádcích (by row) je potřeba v matici zahrnout byrow = TRUE.
matrix(1:6, nrow = 3, ncol = 2, byrow = TRUE) 
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6

Procvičení

  1. Vytvoř následující matici:
  1. Vytvořte matici z následujících vektorů:

Nezapomeňte na existenci NA!

Matice potřebuje, aby všechny řádky (a sloupce) měly totožný počet hodnot. Funkce rbind a cbind tak začne hodnoty v jednotlivých částech opakovat tak dlouho, dokud jich nebude dostatečný počet na to, aby bylo možné fukci provést.

Pojmenování sloupců a řádků

Jak je vidět z předchozího cvičení, stejně jako u vektoru můžeme pojmenovat každou z jednotlivých součástí, totéž můžeme provést i u matic.

matice <- matrix(1:6, 2, 3); matice
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
rownames(matice) #jaka jsou jmena radku
NULL
colnames(matice) #jaka jsou jmena sloupcu
NULL

Pokud chceme přiřadit jména ke sloupcům či řádkům, musíme tak provést přiřazením vektoru o totožné délce.

rownames(matice) <- c("pocetMereni", "pocetProbandu")
colnames(matice) <- c("pokus1", "pokus2", "pokus3")
matice
              pokus1 pokus2 pokus3
pocetMereni        1      3      5
pocetProbandu      2      4      6

Samostatné cvičení

  1. Vytvořte matici, která bude mít 5 sloupců a 2 řádky a bude obsahovat prvních 10 lichých čísel. Následně připojte k matici další sloupec, tentokrát pouze s číslem 2.
    Sloupce pojmenujte pomocí numerických a řádky pomocí charakterových hodnot.

  2. Vytvořte následující matici:

    HARD MODE: JEDEN ŘÁDEK KÓDU NA DRUHOU ÚLOHU A ŽÁDNÉ RBIND

Řešení úlohy 1)

  1. Vytvořte sekvenci lichých čísel (každé číslo objedno od 1 dále) v počtu deseti hodnot.

    seq(by = 2, length.out = 10)
     [1]  1  3  5  7  9 11 13 15 17 19
    #nebo taky samozrejme c(1, 3, 5, 7, 9, 11, 13, 15, 17, 19), ale....
  1. Použij sekvenci jako hodnoty do matice, rozděl je do pěti sloupců a dvou řádků.

    hotovaMatice <- matrix(seq(by = 2, length.out = 10), ncol = 5); hotovaMatice
         [,1] [,2] [,3] [,4] [,5]
    [1,]    1    5    9   13   17
    [2,]    3    7   11   15   19
  1. Připoj k matici další sloupec tvořený vektorem s takovým počtem hodnot jako je počet řádků

    hotovaMatice <- cbind(hotovaMatice, c(2, 2)); hotovaMatice
         [,1] [,2] [,3] [,4] [,5] [,6]
    [1,]    1    5    9   13   17    2
    [2,]    3    7   11   15   19    2
  1. Pojmenuj sloupce a řádky

    colnames(hotovaMatice) <- 1:ncol(hotovaMatice) #fce ncol da zpet pocet sloupcu, stejne jako nrow radku
    rownames(hotovaMatice) <- c("czech", "slovak")
    hotovaMatice
           1 2  3  4  5 6
    czech  1 5  9 13 17 2
    slovak 3 7 11 15 19 2

Řešení úlohy 2)

  1. Jelikož potřebujeme poskládat numerické vektory 15:20 a 37:42 dohromady šestkrát pod sebou, musí být spojené po řádcích. Kromě rbind tuto možnost poskytuje i parametr byrow = TRUE ve funkci matrix.

    #matrix(?, byrow =  TRUE)
  1. Potřebujeme proto vyvořit sekvenci hodnot, které dáme R k dispozici pro vytvoření matice. To znamená, že musíme sestavit sekvenci šestkrát za sebou alternativně opakujících se vektorů 15:20 a 37:42.
    Toho dosáhneme pomocí funkce rep.

    rep(c(15:20, 37:42), 3)
     [1] 15 16 17 18 19 20 37 38 39 40 41 42 15 16 17 18 19 20 37 38 39 40 41 42 15
    [26] 16 17 18 19 20 37 38 39 40 41 42
  1. Je potřeba, aby počet sloupců byl přesně takový, jako je počet hodnot ve vektorech, jinak by se nám nerozdělily do pravidelně se opakujících řádků.

    matrix(rep(c(15:20, 37:42), 3), ncol = length(15:20), byrow = TRUE)
         [,1] [,2] [,3] [,4] [,5] [,6]
    [1,]   15   16   17   18   19   20
    [2,]   37   38   39   40   41   42
    [3,]   15   16   17   18   19   20
    [4,]   37   38   39   40   41   42
    [5,]   15   16   17   18   19   20
    [6,]   37   38   39   40   41   42

Možná vás napadlo, zda by nešlo určit popisky sloupců a řádků už přímo v zadání matice. Je to možné, a to pomocí atributu dimnames.

matrix(1:6, ncol = 3,
       dimnames = list(c("cesko", "slovensko"), 10:12),
       byrow = TRUE)
          10 11 12
cesko      1  2  3
slovensko  4  5  6

Do parametru dimnames se vloží list, který bude obsahovat názvy pro každou dimenzi (zde řádky a sloupce). Co je to ale list?

Seznam (list)

jednodimenzionální objekt složený z jiných objektů, které mohou být rozličné délky a datového typu1

  • use case
    • třeba argument/funkce dimnames (musí se vložit jeden objekt co může mít více data typů)
    • Dvě dimenze: hodnoty v řádcích a sloupcích
  • vytvoří se pomocí funkce list
  • ukázka:
list(name = c("William Hartnell","Patrick Troughton","Jon Pertwee","Tom Baker","Peter Davison","Colin Baker","Sylvester McCoy","Paul McGann", "John Hurt","Christopher Eccleston"),
               year = c(55,46,50,40,29,40,44,36,73,41), 
               episodes = c("134","119","128","172","69","31","42","1","2","13"))
$name
 [1] "William Hartnell"      "Patrick Troughton"     "Jon Pertwee"          
 [4] "Tom Baker"             "Peter Davison"         "Colin Baker"          
 [7] "Sylvester McCoy"       "Paul McGann"           "John Hurt"            
[10] "Christopher Eccleston"

$year
 [1] 55 46 50 40 29 40 44 36 73 41

$episodes
 [1] "134" "119" "128" "172" "69"  "31"  "42"  "1"   "2"   "13" 

Procvičení

  1. Vytvořte objekt, který v sobě bude obsahovat informace o probíhajícím výzkumu. Bude obsahovat jeho název, jména a identifikační číslo dvou výzkumníků a soupis toho, zda se jim podařilo v pěti experimentech octomilky úspěšně rozmnožit.

Data frame

typ listu, který obsahuje pouze objekty totožné délky

  • s vektorem nejčastější typ datové struktury v R, se kterým budete pracovat

  • tldr; tabulka - má dvě dimenze!

  • ukázka

Tvorba data frame

Nejjednoduší působ, jak vytvořit data frame je skrz stejnojmou funkci data.frame.

data.frame(obec = c("Čeladná", "Jáchymov", "Chýně"),
           PSČ = c(73912, 36251, 25303),
           okres = c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"),
           row.names = c("id_01", "id_02", "id_03"))
          obec   PSČ         okres
id_01  Čeladná 73912 Frýdek-Mýstek
id_02 Jáchymov 36251  Karlovy Vary
id_03    Chýně 25303   Praha-západ

Co se stane, pokud se snažíme do data frame vložit objekt, který je jiné délky než zbylé?

Nezapomeňte na existenci NA!

data.frame(obec = c("Čeladná", "Jáchymov", "Chýně"),
           PSČ = c(73912, 36251, NA),
           okres = c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"),
           row.names = c("id_01", "id_02", "id_03"))
          obec   PSČ         okres
id_01  Čeladná 73912 Frýdek-Mýstek
id_02 Jáchymov 36251  Karlovy Vary
id_03    Chýně    NA   Praha-západ

Pojmenovávání sloupců a řádků

  • řádky:

    • pomocí argumentu row.names,vždy potřeba definovat název pro každý řádek!

      data.frame(obec = c("Čeladná", "Jáchymov", "Chýně"),
                 PSČ = c(73912, 36251, 25303),
                 okres = c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"),
                 row.names = c("id_01", "id_02", "id_03"))
                obec   PSČ         okres
      id_01  Čeladná 73912 Frýdek-Mýstek
      id_02 Jáchymov 36251  Karlovy Vary
      id_03    Chýně 25303   Praha-západ
    • pozdější doplnění pomocí funkce rownames

      lokace <- data.frame(obec = c("Čeladná", "Jáchymov", "Chýně"),
                 PSČ = c(73912, 36251, 25303),
                 okres = c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"))
      rownames(lokace) <- c("id_01", "id_02", "id_03")
  • sloupce:

    • pojmenování jednotlivých datových struktur, ze kterých se má data frame skládat, pomocí štítku (název = hodnota)

      data.frame(obec = c("Čeladná", "Jáchymov", "Chýně"),
                 PSČ = c(73912, 36251, 25303),
                 okres = c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"))
            obec   PSČ         okres
      1  Čeladná 73912 Frýdek-Mýstek
      2 Jáchymov 36251  Karlovy Vary
      3    Chýně 25303   Praha-západ
    • použití již dříve vytvořených objektů

      obec <- c("Čeladná", "Jáchymov", "Chýně")
      PSČ <- c(73912, 36251, 25303)
      okres <- c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ")
      
      data.frame(obec, PSČ, okres)
            obec   PSČ         okres
      1  Čeladná 73912 Frýdek-Mýstek
      2 Jáchymov 36251  Karlovy Vary
      3    Chýně 25303   Praha-západ
    • pozdější doplnění pomocí funkce colnames

      lokace <- data.frame(c("Čeladná", "Jáchymov", "Chýně"),
                 c(73912, 36251, 25303),
                 c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"))
      colnames(lokace) <- c("obec", "PSČ", "okres")
      lokace
            obec   PSČ         okres
      1  Čeladná 73912 Frýdek-Mýstek
      2 Jáchymov 36251  Karlovy Vary
      3    Chýně 25303   Praha-západ
  • oboje najednou:

    • použitím funkce dimnames lze najednou nastavit názvy pro obě dimenze

      dimnames(lokace) <- list(c("id_01", "id_02", "id_03"),
                               c("obec", "psc", "okres"))
      lokace
                obec   psc         okres
      id_01  Čeladná 73912 Frýdek-Mýstek
      id_02 Jáchymov 36251  Karlovy Vary
      id_03    Chýně 25303   Praha-západ
      • Proč zde používáme list? Pokud si nepamatujete, podívejte se do nápovědy :]

Jiné způsoby tvorby data frame

Nešlo by ale přeci k vytvoření data frame jednoduše použít cbind nebo rbind? Pojďme si to vyzkoušet.

cbind(c("Čeladná", "Jáchymov", "Chýně"),
      c(73912, 36251, 25303),
      c("Frýdek-Mýstek", "Karlovy Vary", "Praha-západ"))
     [,1]       [,2]    [,3]           
[1,] "Čeladná"  "73912" "Frýdek-Mýstek"
[2,] "Jáchymov" "36251" "Karlovy Vary" 
[3,] "Chýně"    "25303" "Praha-západ"  

Jaký typ objektu je výsledek? Jedná se o data frame?

class vs mode

Funkce mode nám zjistí, o jaký datový typ se jedná. Fuknce class nám nejenomže zjistí více informací, ale hlavně nám řekne, jak se vůči danému objektu R bude chovat.

Funkce cbind a rbind vytvoří data frame pouze v případě, že alespoň jeden z objektů svazovaných dohromady je již data frame, jinak vytvoří matici.

Pro vytvoření data frame pomocí spojení objektů jako sloupců či řádků je třeba využít přímo funkce cbind.data.frame a rbind.data.frame.

Procvičení

  1. Spojte následující vektory po sloupcích do data frame. Následně k němu doplňte jména řádků, které budou libovolný text.

Samostatné cvičení

  1. Vytvořte následující data frame:
  1. Doplňte k data frame z první úlohy sloupec clearSample, který v sobě bude obsahovat náhodně vybrané hodnoty TRUE či FALSE. Výběr hodnot proveďte pomocí funkce.

  2. Z následujících vektorů (bez jejich upravování) vytvořte data frame a pojmenujte první sloupec jako znamky a třetí jako predmety.

sample(1:5, 6, replace = TRUE)
[1] 1 3 2 2 4 1
jmenaZaku <- c("LK", "SD", "AE", "IR"); jmenaZaku
[1] "LK" "SD" "AE" "IR"
rep(c("ČJ", "biologie", "španělština"), 2)
[1] "ČJ"          "biologie"    "španělština" "ČJ"          "biologie"   
[6] "španělština"

Řešení úlohy 1)

  1. Vypište jednotlivé sloupce jako vektory.

    vek <- c(27,35,30,47,42)
    sex <- c("female","male","male","female","female")
    strana <- c("sin","sin","dx","dx","dx")
  1. Volitelné; vytvořte si vektor pro jména řádků.

    id <- c("SC_001", "SC_007", "SC_013", "SC_014", "SC_020")
  1. Pomocí funkce data.frame spojte sloupce dohromady a popište řádky.

    vzorek <- data.frame(vek, strana, sex, row.names = id); vzorek
           vek strana    sex
    SC_001  27    sin female
    SC_007  35    sin   male
    SC_013  30     dx   male
    SC_014  47     dx female
    SC_020  42     dx female

Pojmenování výsledného data frame

Data frame si nemusíte pojmenovávat, ale vzhledem k úloze 2) se to hodí.

Řešení úlohy 2)

  1. K data frame potřebujeme připojit nový sloupec. Jeden ze způsobů jak to provést (další se naučíme později) je vytvoření nového pojmenovaného vektoru s jeho připojení ke stávajícímu data frame. Vytvořme si proto vektor, který bude obsahovat náhodný výběr boolean hodnot.

    clearSample <- sample(c(TRUE, FALSE),
                   size = length(strana), replace = TRUE)
    #potrebujeme tolik hodnot jako je jich v teremkoliv jinem sloupci
    #proto pouzijeme length(nazev nami ulozeneho vektoru)
      #ano, jde to pocitat i rucne
        #ale co kdyz toho budete mit opravdu hodne?
  1. Spojíme dohromady data frame z první úlohy a nový vektor. Pro snadnou práci doporučuji si data frame pojmenovat (viz předchozí úloha).

    vzorek <- cbind.data.frame(vzorek, clearSample); vzorek
           vek strana    sex clearSample
    SC_001  27    sin female       FALSE
    SC_007  35    sin   male       FALSE
    SC_013  30     dx   male       FALSE
    SC_014  47     dx female        TRUE
    SC_020  42     dx female       FALSE
    #rovnou si i výsledek znovu uložíme

Opakované spuštění ukládání kódu s novými údaji

Co se stane, pokud výše zmíněný kód projedeme několikrát? A proč?

Při opakovaném spuštění kódu, kde se přidávají/ubírají části objektu anásledně se výsledek ukládá pod totožným názvem, bude docházet k tomu, že se změny provedou vždy na výsledku předchozí iterace. Opakovaným spouštěním kódu a jeho ukládáním v této úloze by tak docházelo k opakovanému přidávání sloupce clearSample ad nauseum.

Řešení úlohy 3)

  1. Jednoduchým způsobem, jak si vytvořit dataframe s přiřazováním názvů, je použít funkci data.frame. Vytvořme si proto data frame z dodaných vektorů a dle zadání je pojmenujme tak, aby nám z toho vznikly správné názvy sloupců.

Proč nepojmenováváme vektor, který v sobě obsahuje jména žáků?

Protože tím, že jsme si vektor přiřadili k určitému názvu, tak už v sobě obsahuje informace o jménu, které R použije jako název sloupce.

  1. Kód nám hodí error, jelikož se pokoušíme do data frame, který musí mít vždy stejnou délku sloupců či řádků, vložit vektor, který je kratší jak ostatní. Potřebujeme si tedy zjistit, o který se jedná.
length(sample(1:5, 6, replace = TRUE))
[1] 6
length(jmenaZaku)
[1] 4
length(rep(c("ČJ", "biologie", "španělština"), 2))
[1] 6

Vidíme, že vektor jmenaZaku je o dvě hodnoty kratší jak ostatní. Abychom mohli data frame i tak stvořit, je potřeba, abychom upravili délku sloupce, který obsahuje vektor jmenaZaku na stejný počet hodnot jako ostatní.

  1. Pokud potřebujeme přidat chybějící hodnoty, jednoduše použijeme NA. Zadání nám ovšem neumožňuje upravovat vlastní vektor jmenaZaku. Jak jinak můžeme NA hodnoty v data frame doplnit?

Nic nám nezakazuje použít vektor uvnitř dalšího vektoru.

data.frame(znamky = sample(1:5, 6, replace = TRUE),
           jmenaZaku = c(jmenaZaku, NA, NA),
           predmety = rep(c("ČJ", "biologie", "španělština"), 2))
  znamky jmenaZaku    predmety
1      2        LK          ČJ
2      2        SD    biologie
3      5        AE španělština
4      1        IR          ČJ
5      5      <NA>    biologie
6      1      <NA> španělština

Tibble

data frame ale ✧・゚: ✧・゚:vylepšené:・゚✧:・゚✧

  • stejná funkce jako data frame, ale v některých oblastech vylepšená

    • ukazuje například rovnou rozměry a data typy jednotlivých sloupců

    • snadněji zvládá objemnější datasety

  • ukázka:

  tibble::tibble(
    id = 1:4,
    jmeno = c("Ivo", "Oto", "Anna", "Bára"),
    vek = c(25, 29,30, 35),
    role = c("Engineer", "Data Scientist", "Developer", "HR"),
    plat = c(45000,60000, 80000, 100000)
  )
# A tibble: 4 × 5
     id jmeno   vek role             plat
  <int> <chr> <dbl> <chr>           <dbl>
1     1 Ivo      25 Engineer        45000
2     2 Oto      29 Data Scientist  60000
3     3 Anna     30 Developer       80000
4     4 Bára     35 HR             100000
  • Funkce tibble není součástí základního R, ale je v balíčku tibble, který je následně součástí metabalíčku tidyverse.

Balíčky v R

S balíčky jsme se krátce seznámili již v první lekci, zde si je ale probereme podrobněji.

Co je to balíček (package)?

  • nezávisle vytvořená sada funkcí, objektů a dat, které slouží k vyřešení určitého problému a které je možné si stáhnout a používat

    • proč si ručně vytvářet celou novou funkci, která by nám třídila data dle námi daných kategoií, když to již někdo vytvořil jako funkci group_by v balíčku dlyr?

Jak ho získám?

  1. funkce install.packages("název balíčku")

  2. výběrem skrz rozhraní

Spuštění balíčku

Po instalaci/stažení se nám balíček uloží v počítači, Před tím, než ho budeme používat, tak ho musíme do R nahrát; říci mu, že v tuto chvíli má hledat spuštěné funkce nejenom v base R , ale i v dalších místech na našem počítači.

Proč se balíčky nenahrávají automaticky?

Každý nahraný a otevřený balíček zabírá místo - pokud bychom automaticky nahrávali veškeré stažené balíčky, R by se nám velmi výrazně zpomalilo.

Jak si balíček nahrajeme do R?

  1. pomocí funkce library(název balíčku)1

  2. výběrem skrze rozhraní

Konflikty v balíčcích

Je možné, že dva či více balíčků budou obsahovat funkci s totožným názvem. Jak potom R pozná, z kterého balíčku má danou funkci použít?

Nejnověji nahraný balíček má prioritu

Při nahrávání balíčků má nejnověji nahraný balíček vždy prioritu nad dříve nahranými balíčky. Pokud si ráno nahrajete balíček 1 s funkcí x a odpoledne balíček 2, taktéž s funkcí x a funkci začnete používat, bude použita funkce x z balíčku 2.

Co když si nechci nahrát celý balíček/chci použít verze funkce ze specifického balíčku?

R umožňuje nahrávat funkce ze specifických balíčků tak, aby “nepřepsaly” již používané funkce. A to pomocí symbolu ::.

název balíčku::funkce

tabulka <- tibble::tibble(
  id = 1:4,
  jmeno = c("Ivo", "Oto", "Anna", "Bára"),
  vek = c(25, 29,30, 35),
  role = c("Engineer", "Data Scientist", "Developer", "HR"),
  plat = c(45000,60000, 80000, 100000)
); tabulka
# A tibble: 4 × 5
     id jmeno   vek role             plat
  <int> <chr> <dbl> <chr>           <dbl>
1     1 Ivo      25 Engineer        45000
2     2 Oto      29 Data Scientist  60000
3     3 Anna     30 Developer       80000
4     4 Bára     35 HR             100000

Pomocí funkce tibble ze stejnojmenného balíčku jsme si vytvořili tibble tabulku.

Příprava na další hodinu

Nainstalujte si balíček tidyverse. Počítejte s tím, že balíček se bude stahovat a instalovat klidně i několik desítek minut - záleží na vašem počítači.

Domácí úkol

  1. Vytvořte vektor, který v sobě bude mít větu “Tea is better than coffee”. Pokuste se přijít na to, jakým způsobem byste mohli z tohoto vektoru vytvořit druhý vektor, co bude obsahovat hodnoty “Tea” “is” “better” “than” “coffee”. Nezapomeňte, StackOverflow a jiné stránky jsou vaši nejlepší kamarádi ;)

  2. Vytvořte list, který bude obsahovat informace o vašem oblíbeném filmu; jeho název, kdo jej režiséroval, kdy byl vydán, alespoň tři jména herců a hereček, kteří v něm hráli, na jaké ceny byl nominován a jaké společnosti se angažovaly jako jeho producenti. Jakmile budete mít list vytvořený, připojte do seznamu herců/hereček Zaphoda Beeblebroxe. Pokuste se připojení provést pomocí (nové) funkce, ale pokud naleznete jiný a jednodušší způsob jak toto provést, který jsme si ještě neukazovali, zkuste použít ten :).

  3. Kolik odlišných hodnot je v následujícím vektoru?

c(3, 2, 7, 45, 2, 6, 11, 7,
  90, 76, 4, 3, 46, 45, 7,
  89, 6, 45, 1, 55, 12, 90,
  2, 67, 2, 8, 7, 4, 34, 6)
 [1]  3  2  7 45  2  6 11  7 90 76  4  3 46 45  7 89  6 45  1 55 12 90  2 67  2
[26]  8  7  4 34  6

Skript zašlete nejpozději do pátku před příští hodinou na lucie.hoskova@ruk.cuni.cz