Zpět na přehled cvičení

Rkový skript ke stažení: R

Co si zde představíme?

Data.frame

Data většinou máme uložená v nějaké tabulce, ale analyzovat je pomocí matrix není zrovna ideální. Například proto, že všechny prvky matice musí být stejného druhu:

A <- matrix(1:6, nrow = 3, ncol = 2)
class(A); class(A[1,1])
## [1] "matrix" "array"
## [1] "integer"
A[1,2] <- "a"            # změníme jeden prvek na string
A                        # všechny prvky se změní na string
##      [,1] [,2]
## [1,] "1"  "a" 
## [2,] "2"  "5" 
## [3,] "3"  "6"
class(A[1,1])
## [1] "character"

Jenže naše data se často sestávají nejen z numerických hodnot, ale také kategorií, časových údajů a dalších. Objekt data.frame umožňuje pospojovat různé typy v jednom objektu. Jedná se nakonec o matici s pojmenovanými sloupci, kde každý sloupec může být jiné třídy:

jmeno <- c("Aleš", "Barbora", "Ctirad", "Drahomíra")     # vektor jmen
narozeni <- as.Date(c("1992-03-15", "2006-12-01", "1998-07-07", "1977-05-31")) # vektor dat narození
vyska <- c(1.81, 1.77, 1.66, 1.79)                       # vektor výšek
pohlavi <- factor(c("Muž", "Žena", "Muž", "Žena"))       # faktor pohlaví
lide <- data.frame(jmeno, narozeni, vyska, pohlavi)      # data objekt DATA.FRAME
lide
##       jmeno   narozeni vyska pohlavi
## 1      Aleš 1992-03-15  1.81     Muž
## 2   Barbora 2006-12-01  1.77    Žena
## 3    Ctirad 1998-07-07  1.66     Muž
## 4 Drahomíra 1977-05-31  1.79    Žena
str(lide)                                                # výpis sloupců, jejich typů a pár hodnot
## 'data.frame':    4 obs. of  4 variables:
##  $ jmeno   : chr  "Aleš" "Barbora" "Ctirad" "Drahomíra"
##  $ narozeni: Date, format: "1992-03-15" "2006-12-01" "1998-07-07" ...
##  $ vyska   : num  1.81 1.77 1.66 1.79
##  $ pohlavi : Factor w/ 2 levels "Muž","Žena": 1 2 1 2
head(lide)                                               # prvních pár řádků
##       jmeno   narozeni vyska pohlavi
## 1      Aleš 1992-03-15  1.81     Muž
## 2   Barbora 2006-12-01  1.77    Žena
## 3    Ctirad 1998-07-07  1.66     Muž
## 4 Drahomíra 1977-05-31  1.79    Žena
tail(lide)                                               # posledních pár řádků
##       jmeno   narozeni vyska pohlavi
## 1      Aleš 1992-03-15  1.81     Muž
## 2   Barbora 2006-12-01  1.77    Žena
## 3    Ctirad 1998-07-07  1.66     Muž
## 4 Drahomíra 1977-05-31  1.79    Žena
summary(lide)                                            # summary respektující jednotlivé typy proměnných
##     jmeno              narozeni              vyska       pohlavi 
##  Length:4           Min.   :1977-05-31   Min.   :1.660   Muž :2  
##  Class :character   1st Qu.:1988-07-03   1st Qu.:1.742   Žena:2  
##  Mode  :character   Median :1995-05-11   Median :1.780           
##                     Mean   :1993-10-05   Mean   :1.758           
##                     3rd Qu.:2000-08-12   3rd Qu.:1.795           
##                     Max.   :2006-12-01   Max.   :1.810
dim(lide)                                                # rozměry datasetu (jako u matice)
## [1] 4 4
nrow(lide)                                               # počet řádků datasetu
## [1] 4
ncol(lide)                                               # počet sloupců
## [1] 4

Sloupce lze z datasetu vybrat několika způsoby:

lide[, "jmeno"]
## [1] "Aleš"      "Barbora"   "Ctirad"    "Drahomíra"
lide$narozeni
## [1] "1992-03-15" "2006-12-01" "1998-07-07" "1977-05-31"
lide[["vyska"]]
## [1] 1.81 1.77 1.66 1.79
lide[, 4]
## [1] Muž  Žena Muž  Žena
## Levels: Muž Žena
colnames(lide)                        # přehled názvů sloupců
## [1] "jmeno"    "narozeni" "vyska"    "pohlavi"
k <- which(colnames(lide) == "vyska") # který sloupec je sloupec s výškou
colnames(lide)[k] <- "Výška"          # přejmenování sloupce
lide$Výška                            # trochu se divím, že zde funguje česká diakritika, raději NEDĚLEJTE!
## [1] 1.81 1.77 1.66 1.79
colnames(lide)[k] <- "Výška [m]"      # zde už je v názvu mezera, která to trochu komplikuje
lide$`Výška [m]`                      # je třeba obalit do `` (Alt Gr + 7 na české klávesnici)
## [1] 1.81 1.77 1.66 1.79
colnames(lide)[k] <- "vyska"          # preferovaný styl pracovního názvu

Řádky si lze také pojmenovat a pak je vybírat pomocí jmen:

rownames(lide)                   # zatím nepojmenované, 1:4 je default
## [1] "1" "2" "3" "4"
rownames(lide) <- lide$jmeno     # použití jednoho sloupce s jednoznačným identifikátorem 
lide
##               jmeno   narozeni vyska pohlavi
## Aleš           Aleš 1992-03-15  1.81     Muž
## Barbora     Barbora 2006-12-01  1.77    Žena
## Ctirad       Ctirad 1998-07-07  1.66     Muž
## Drahomíra Drahomíra 1977-05-31  1.79    Žena
lide["Ctirad", "narozeni"]       # už lze použít jméno k adresování řádku
## [1] "1998-07-07"
lide[3, "narozeni"]              # stále lze pomocí čísla řádku
## [1] "1998-07-07"

Do existujícího datasetu lze přidávat řádku jen velmi komplikovaně, protože se musí dodržet pořadí a typ všech proměnných:

c("Evžen", as.Date("1999-09-09"), 1.99, "Muž")  # už jen vektor pojme vše jako charakter
## [1] "Evžen" "10843" "1.99"  "Muž"
lide[5, "jmeno"] <- "Evžen"                     # vznik pátého řádku
lide                                            # ostatní proměnné jsou zatím NA
##               jmeno   narozeni vyska pohlavi
## Aleš           Aleš 1992-03-15  1.81     Muž
## Barbora     Barbora 2006-12-01  1.77    Žena
## Ctirad       Ctirad 1998-07-07  1.66     Muž
## Drahomíra Drahomíra 1977-05-31  1.79    Žena
## 5             Evžen       <NA>    NA    <NA>
lide[5, "narozeni"] <- "1999-09-09"             # stačí jako charakter
lide[5, "vyska"] <- 1.99
lide[5, "pohlavi"] <- "Muž"                     # stačí jako charakter
rownames(lide) <- lide$jmeno
summary(lide)                                   # Rko samo převedlo na příslušný typ sloupce
##     jmeno              narozeni              vyska       pohlavi 
##  Length:5           Min.   :1977-05-31   Min.   :1.660   Muž :3  
##  Class :character   1st Qu.:1992-03-15   1st Qu.:1.770   Žena:2  
##  Mode  :character   Median :1998-07-07   Median :1.790           
##                     Mean   :1994-12-12   Mean   :1.804           
##                     3rd Qu.:1999-09-09   3rd Qu.:1.810           
##                     Max.   :2006-12-01   Max.   :1.990
# lide[5, "narozeni"] <- "1999-99-99"           # stěžuje si, že takové datum neexistuje --> error
# lide[5, "pohlavi"] <- "Neznámé"               # stěžuje si, že takový level neexistuje --> warning, NA
# Další způsob je pomocí rbind(), ale musí být dodrženy stejné sloupce a typy.
# Ukážeme si přidání jednoho již exitujícího řádku.
lide <- rbind(lide, lide[5,])
lide                                            # všimněte si úpravy jména řádku
##               jmeno   narozeni vyska pohlavi
## Aleš           Aleš 1992-03-15  1.81     Muž
## Barbora     Barbora 2006-12-01  1.77    Žena
## Ctirad       Ctirad 1998-07-07  1.66     Muž
## Drahomíra Drahomíra 1977-05-31  1.79    Žena
## Evžen         Evžen 1999-09-09  1.99     Muž
## Evžen1        Evžen 1999-09-09  1.99     Muž
lide <- lide[-6,]                               # odstranění řádku 
# Další způsob je přidání jako listu
dalsi_lide <- list(jmeno = c("Františka", "Goliáš"),
                   narozeni = c("2000-01-01", "1234-02-02"),
                   vyska = c(1.67, 2.3),
                   pohlavi = c("Žena", "Muž"))
as.data.frame(dalsi_lide)                       # převod listu na data.frame
##       jmeno   narozeni vyska pohlavi
## 1 Františka 2000-01-01  1.67    Žena
## 2    Goliáš 1234-02-02  2.30     Muž
lide <- rbind(lide, dalsi_lide)                 # spojení datasetu a listu (automaticky převede)
rownames(lide) <- lide$jmeno                    # pojmenování řádků

Spojování dvou datasetů v jeden lze obecně provádět pomocí funkce merge. Ta si najde společné sloupce oběma datasetům a na nich sjednotí řádky, aby nedocházelo k duplikacím. Doporučuji si projít help(merge) pro plné vysvětlení, zde jen pár ukázek:

# Nejprve si vyrobíme pracovní datasety, které nemusí obsahovat totožné řádky ani sloupce
lide1 <- lide[1:5, c("jmeno", "vyska", "pohlavi")]
lide2 <- lide[4:7, c("jmeno", "narozeni", "vyska")]

# Bez merge by člověk musel dávat pozor na duplicitní pozorování
lide_spoj <- rbind(lide[1:5,], lide[4:7,])  # takto by se spojily, ale vznikla by duplicitní pozorování
duplicated(lide_spoj)                       # indikátor duplicitních řádků
## [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE
lide_spoj[!duplicated(lide_spoj), ]         # pouze neduplicitní řádky
##               jmeno   narozeni vyska pohlavi
## Aleš           Aleš 1992-03-15  1.81     Muž
## Barbora     Barbora 2006-12-01  1.77    Žena
## Ctirad       Ctirad 1998-07-07  1.66     Muž
## Drahomíra Drahomíra 1977-05-31  1.79    Žena
## Evžen         Evžen 1999-09-09  1.99     Muž
## Františka Františka 2000-01-01  1.67    Žena
## Goliáš       Goliáš 1234-02-02  2.30     Muž
unique(lide_spoj)                           # to samé - funkce unique() u data.framu funguje po řádcích
##               jmeno   narozeni vyska pohlavi
## Aleš           Aleš 1992-03-15  1.81     Muž
## Barbora     Barbora 2006-12-01  1.77    Žena
## Ctirad       Ctirad 1998-07-07  1.66     Muž
## Drahomíra Drahomíra 1977-05-31  1.79    Žena
## Evžen         Evžen 1999-09-09  1.99     Muž
## Františka Františka 2000-01-01  1.67    Žena
## Goliáš       Goliáš 1234-02-02  2.30     Muž
# Základni použití merge()
merge(lide1, lide2)                         # jako default provádí průnik obou datasetů
##       jmeno vyska pohlavi   narozeni
## 1 Drahomíra  1.79    Žena 1977-05-31
## 2     Evžen  1.99     Muž 1999-09-09
merge(lide1, lide2, all.x = TRUE)           # všichni, co jsou obsaženi v prvním datasetu (neznámé info = NA)
##       jmeno vyska pohlavi   narozeni
## 1      Aleš  1.81     Muž       <NA>
## 2   Barbora  1.77    Žena       <NA>
## 3    Ctirad  1.66     Muž       <NA>
## 4 Drahomíra  1.79    Žena 1977-05-31
## 5     Evžen  1.99     Muž 1999-09-09
merge(lide1, lide2, all.y = TRUE)           # všichni obsažení ve druhém datasetu (neznámé info = NA)
##       jmeno vyska pohlavi   narozeni
## 1 Drahomíra  1.79    Žena 1977-05-31
## 2     Evžen  1.99     Muž 1999-09-09
## 3 Františka  1.67    <NA> 2000-01-01
## 4    Goliáš  2.30    <NA> 1234-02-02
merge(lide1, lide2, all = TRUE)             # všechny řádky všech datasetů (neznámé info = NA)
##       jmeno vyska pohlavi   narozeni
## 1      Aleš  1.81     Muž       <NA>
## 2   Barbora  1.77    Žena       <NA>
## 3    Ctirad  1.66     Muž       <NA>
## 4 Drahomíra  1.79    Žena 1977-05-31
## 5     Evžen  1.99     Muž 1999-09-09
## 6 Františka  1.67    <NA> 2000-01-01
## 7    Goliáš  2.30    <NA> 1234-02-02
# Lze ovlivňovat, přes jaké sloupce se merguje (jinak spojuje přes všechny společné)
merge(lide1, lide2, by = "jmeno", all = T)  # spojuje se jen přes sloupec jméno, 
##       jmeno vyska.x pohlavi   narozeni vyska.y
## 1      Aleš    1.81     Muž       <NA>      NA
## 2   Barbora    1.77    Žena       <NA>      NA
## 3    Ctirad    1.66     Muž       <NA>      NA
## 4 Drahomíra    1.79    Žena 1977-05-31    1.79
## 5     Evžen    1.99     Muž 1999-09-09    1.99
## 6 Františka      NA    <NA> 2000-01-01    1.67
## 7    Goliáš      NA    <NA> 1234-02-02    2.30
                                            # sloupec vyska je sice v obou datasetech, ale máme .x a .y verze

lide1[4, "jmeno"] <- "Denisa"               # změna jména v jednom z datasetů
merge(lide1, lide2)                         # řádky pro Denisu a Drahomíru se liší v jediné hodnotě 
##   jmeno vyska pohlavi   narozeni
## 1 Evžen  1.99     Muž 1999-09-09
                                            # zachází se tedy s nimi jako s odlišnými
merge(lide1, lide2, all = TRUE)             # zvláštní řádky jak pro Denisu a Drahomíru
##       jmeno vyska pohlavi   narozeni
## 1      Aleš  1.81     Muž       <NA>
## 2   Barbora  1.77    Žena       <NA>
## 3    Ctirad  1.66     Muž       <NA>
## 4    Denisa  1.79    Žena       <NA>
## 5 Drahomíra  1.79    <NA> 1977-05-31
## 6     Evžen  1.99     Muž 1999-09-09
## 7 Františka  1.67    <NA> 2000-01-01
## 8    Goliáš  2.30    <NA> 1234-02-02
merge(lide1, lide2, by = "vyska", all = T)  # spojuje se jen přes sloupec vyska, (!naštěstí! zde vše různé) 
##   vyska jmeno.x pohlavi   jmeno.y   narozeni
## 1  1.66  Ctirad     Muž      <NA>       <NA>
## 2  1.67    <NA>    <NA> Františka 2000-01-01
## 3  1.77 Barbora    Žena      <NA>       <NA>
## 4  1.79  Denisa    Žena Drahomíra 1977-05-31
## 5  1.81    Aleš     Muž      <NA>       <NA>
## 6  1.99   Evžen     Muž     Evžen 1999-09-09
## 7  2.30    <NA>    <NA>    Goliáš 1234-02-02
                                            # až na Denisu a Drahomíru, které to spojilo v jeden řádek 

Do existujícího datasetu lze jednoduše přidávat další sloupce:

lide$vaha <- c(95, 71, 67, 84, 99, 70, 166)                     # přidání váhy do již stvořeného datasetu
lide$presny_vek <- difftime("2025-10-15", lide$narozeni)/365.25 # skutečný přesný věk
lide$vek <- floor(as.numeric(lide$presny_vek))                  # useknutý věk na dolní celou část 
lide <- transform(lide, 
                  bmi = vaha/vyska^2,                           # vytvoření nového sloupce transformací jiných
                  # fbmi = cut(bmi, breaks = c(0, 25, Inf), labels = c("Norma", "Obezita")) # ještě bmi nezná!
                  vyska_cm = vyska * 100                        # výška v centimetrech
                  )                                             # lze mít pro přehlednost až na dalším řádku   
# Přidání sloupce, který identifikuje obézního jedince lze udělat několika způsoby
# 1. třeba otrocky postupně
lide$obezita <- rep(1, nrow(lide))      # sloupec jedniček 
lide$obezita[lide$bmi <= 25] <- 0       # těm, kteří mají BMI <= 25, bude hodnota přepsána na 0     
lide$obezita <- factor(lide$obezita, levels = c(0,1), labels = c("Norma", "Obezita")) # převedení na faktor
# 2. použitím funkce cut(), kterou známe ze cvičení o faktorech
lide$fbmi <- cut(lide$bmi, breaks = c(0, 25, Inf), labels = c("Norma", "Obezita"))
# Sami si zkuste nadefinovat proměnnou "projde_dvermi" tedy, zda dotyčný projde dveřmi o 180 cm bez přikrčení

Někdy může být otravné neustále psát jmeno_data.framu$.... Existuje způsob, jak z názvů sloupců udělat prozatímní proměnné a adresovat se na ně jen pomocí nich. Má to ale svá úskalí, se kterými je třeba počítat.

with(lide, 0.5*vek + 1.1*vyska - 0.1*vaha) # prováděj SE sloupci daného datasetu cokoliv (jednorázové)
## [1]   8.991   3.847   8.626  17.569   5.289   7.337 381.430
vyska                                      # sloupec výšek existující v našem prostředí
## [1] 1.81 1.77 1.66 1.79
vyska[1] <- 1.88                           # změna jedné hodnoty výšky
lide$vyska                                 # nezměnilo v datasetu
## [1] 1.81 1.77 1.66 1.79 1.99 1.67 2.30
attach(lide)                               # nyní lze sloupci datasetu volat rovnou
## The following objects are masked _by_ .GlobalEnv:
## 
##     jmeno, narozeni, pohlavi, vyska
0.5*vek + 1.1*bmi - 0.1*vaha               # nemusíme psát lide$vaha apod.
## [1]  38.89768  26.82898  33.54554  44.43805  30.59931  33.10945 413.41796
vyska                                      # tahle proměnná již existovala v prostředí - odkazuje stále na ni
## [1] 1.88 1.77 1.66 1.79
lide$nad30 <- cut(vek, breaks = c(0, 30, Inf), # lze stále přidávat do datasetu 
                  labels = c("<30", "30+"), right = FALSE) # zleva uzavřené intervaly
# nad30 # tento objekt nelze získat bez lide$ (leda byste zase spustili attach(lide))
detach(lide)                               # ukončení zpřístupnění názvu sloupců
vyska                                      # původní vektor výšek stále zná
## [1] 1.88 1.77 1.66 1.79
# vaha                                     # tento objekt už nezná

Základní explorace dat

Pokračujme v našem příkladu s datasetem s několika lidmi. Cílem této části bude provést zevrubný průzkum dostupných dat. Základní přehled o datasetu získáme pomocí jednoduchých funkcí:

str(lide)                 # výpis sloupců, jejich typů a pár hodnot
## 'data.frame':    7 obs. of  12 variables:
##  $ jmeno     : chr  "Aleš" "Barbora" "Ctirad" "Drahomíra" ...
##  $ narozeni  : Date, format: "1992-03-15" "2006-12-01" "1998-07-07" ...
##  $ vyska     : num  1.81 1.77 1.66 1.79 1.99 1.67 2.3
##  $ pohlavi   : Factor w/ 2 levels "Muž","Žena": 1 2 1 2 1 2 1
##  $ vaha      : num  95 71 67 84 99 70 166
##  $ presny_vek: 'difftime' num  33.5849874515172 18.8717773214693 27.2742413871777 48.3748574036048 ...
##   ..- attr(*, "units")= chr "days"
##  $ vek       : num  33 18 27 48 26 25 791
##  $ bmi       : num  29 22.7 24.3 26.2 25 ...
##  $ vyska_cm  : num  181 177 166 179 199 167 230
##  $ obezita   : Factor w/ 2 levels "Norma","Obezita": 2 1 1 2 1 2 2
##  $ fbmi      : Factor w/ 2 levels "Norma","Obezita": 2 1 1 2 1 2 2
##  $ nad30     : Factor w/ 2 levels "<30","30+": 2 1 1 2 1 1 2
head(lide)                # prvních pár řádků
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Aleš           Aleš 1992-03-15  1.81     Muž   95 33.58499 days  33 28.99789      181 Obezita Obezita   30+
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Ctirad       Ctirad 1998-07-07  1.66     Muž   67 27.27424 days  27 24.31412      166   Norma   Norma   <30
## Drahomíra Drahomíra 1977-05-31  1.79    Žena   84 48.37486 days  48 26.21641      179 Obezita Obezita   30+
## Evžen         Evžen 1999-09-09  1.99     Muž   99 26.09970 days  26 24.99937      199   Norma   Norma   <30
## Františka Františka 2000-01-01  1.67    Žena   70 25.78759 days  25 25.09950      167 Obezita Obezita   <30
dim(lide)                 # rozměry datasetu (jako u matice)
## [1]  7 12
summary(lide)             # summary respektující jednotlivé typy proměnných
##     jmeno              narozeni              vyska       pohlavi       vaha          presny_vek         
##  Length:7           Min.   :1234-02-02   Min.   :1.660   Muž :4   Min.   : 67.00   Min.   : 18.87 days  
##  Class :character   1st Qu.:1984-10-22   1st Qu.:1.720   Žena:3   1st Qu.: 70.50   1st Qu.: 25.94 days  
##  Mode  :character   Median :1998-07-07   Median :1.790            Median : 84.00   Median : 27.27 days  
##                     Mean   :1886-12-22   Mean   :1.856            Mean   : 93.14   Mean   :138.81 days  
##                     3rd Qu.:1999-11-05   3rd Qu.:1.900            3rd Qu.: 97.00   3rd Qu.: 40.98 days  
##                     Max.   :2006-12-01   Max.   :2.300            Max.   :166.00   Max.   :791.68 days  
##       vek             bmi           vyska_cm        obezita       fbmi   nad30  
##  Min.   : 18.0   Min.   :22.66   Min.   :166.0   Norma  :3   Norma  :3   <30:4  
##  1st Qu.: 25.5   1st Qu.:24.66   1st Qu.:172.0   Obezita:4   Obezita:4   30+:3  
##  Median : 27.0   Median :25.10   Median :179.0                                  
##  Mean   :138.3   Mean   :26.24   Mean   :185.6                                  
##  3rd Qu.: 40.5   3rd Qu.:27.61   3rd Qu.:190.0                                  
##  Max.   :791.0   Max.   :31.38   Max.   :230.0

Poslední příkaz nám nabízí přehled výběrových charakteristik marginálních rozdělení. Vypíše popisné charakteristiky pro numerické (i časové) proměnné (kvantily, průměr, ale ne směrodatnou odchylku) a četnosti kategorií faktorových proměnných. U numerických veličin se tak dozvíme rozpětí hodnot, na kterém se pohybuje (min, max), dále třeba symetrii či šikmost rozdělení (podobný průměr s mediánem, stejně vzdálené Q1 a Q3). Minimum, maximum a průměr jsou velmi náchylné na odlehlá pozorování (outlieři), stačí se podívat na příklad Goliáše:

summary(lide$vek)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    18.0    25.5    27.0   138.3    40.5   791.0
lide[lide$vek > 40, ]
##               jmeno   narozeni vyska pohlavi vaha     presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Drahomíra Drahomíra 1977-05-31  1.79    Žena   84  48.37486 days  48 26.21641      179 Obezita Obezita   30+
## Goliáš       Goliáš 1234-02-02  2.30     Muž  166 791.68218 days 791 31.37996      230 Obezita Obezita   30+
summary(lide$vyska)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.660   1.720   1.790   1.856   1.900   2.300
lide[(lide$vyska > 2) & (lide$vek > 40), ]
##         jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Goliáš Goliáš 1234-02-02   2.3     Muž  166 791.6822 days 791 31.37996      230 Obezita Obezita   30+
golias <- which((lide$vyska > 2) & (lide$vek > 40))
# výběr jen numerických veličin
numericke <- which(sapply(1:ncol(lide), function(j){is.numeric(lide[,j])}))
summary(lide[-golias, numericke])                 # bez Goliáše
##      vyska            vaha            vek             bmi           vyska_cm    
##  Min.   :1.660   Min.   :67.00   Min.   :18.00   Min.   :22.66   Min.   :166.0  
##  1st Qu.:1.695   1st Qu.:70.25   1st Qu.:25.25   1st Qu.:24.49   1st Qu.:169.5  
##  Median :1.780   Median :77.50   Median :26.50   Median :25.05   Median :178.0  
##  Mean   :1.782   Mean   :81.00   Mean   :29.50   Mean   :25.38   Mean   :178.2  
##  3rd Qu.:1.805   3rd Qu.:92.25   3rd Qu.:31.50   3rd Qu.:25.94   3rd Qu.:180.5  
##  Max.   :1.990   Max.   :99.00   Max.   :48.00   Max.   :29.00   Max.   :199.0
summary(lide[, numericke])                        # s Goliášem
##      vyska            vaha             vek             bmi           vyska_cm    
##  Min.   :1.660   Min.   : 67.00   Min.   : 18.0   Min.   :22.66   Min.   :166.0  
##  1st Qu.:1.720   1st Qu.: 70.50   1st Qu.: 25.5   1st Qu.:24.66   1st Qu.:172.0  
##  Median :1.790   Median : 84.00   Median : 27.0   Median :25.10   Median :179.0  
##  Mean   :1.856   Mean   : 93.14   Mean   :138.3   Mean   :26.24   Mean   :185.6  
##  3rd Qu.:1.900   3rd Qu.: 97.00   3rd Qu.: 40.5   3rd Qu.:27.61   3rd Qu.:190.0  
##  Max.   :2.300   Max.   :166.00   Max.   :791.0   Max.   :31.38   Max.   :230.0
# Hromadný výpočet dalších statistik - po sloupcích
apply(lide[,numericke], 2, sd)                                      # směrodatná odchylka
##       vyska        vaha         vek         bmi    vyska_cm 
##   0.2243403  34.4936157 287.9720555   2.9824947  22.4340303
apply(lide[,numericke], 2, quantile, probs = c(.025, .975))         # hraniční kvantily
##        vyska   vaha    vek      bmi vyska_cm
## 2.5%  1.6615  67.45  19.05 22.91042   166.15
## 97.5% 2.2535 155.95 679.55 31.02265   225.35
timeSeries::colSkewness(lide[,numericke])                           # šikmost   (funkce z balíčku timeSeries)
##     vyska      vaha       vek       bmi  vyska_cm 
## 0.9515779 1.2011086 1.6162845 0.5421598 0.9515779
timeSeries::colKurtosis(lide[,numericke])                           # špičatost (funkce z balíčku timeSeries)
##       vyska        vaha         vek         bmi    vyska_cm 
## -0.63001360 -0.05544623  0.78863998 -1.30652671 -0.63001360

U numerických proměnných je občas žádoucí centrování, tedy odečtení průměru a naškálování na bezrozměrnou veličinu o jednotkovém rozptylu:

scale(lide[,numericke])                                # Silně ovlivněno Goliášem
##                vyska        vaha        vek         bmi   vyska_cm
## Aleš      -0.2037721  0.05384019 -0.3656109  0.92517410 -0.2037721
## Barbora   -0.3820726 -0.64194074 -0.4176993 -1.19894879 -0.3820726
## Ctirad    -0.8723991 -0.75790423 -0.3864462 -0.64524611 -0.8723991
## Drahomíra -0.2929223 -0.26505940 -0.3135225 -0.00742895 -0.2929223
## Evžen      0.5985804  0.16980368 -0.3899188 -0.41549054  0.5985804
## Františka -0.8278240 -0.67093161 -0.3933913 -0.38191701 -0.8278240
## Goliáš     1.9804097  2.11219211  2.2665890  1.72385729  1.9804097
## attr(,"scaled:center")
##      vyska       vaha        vek        bmi   vyska_cm 
##   1.855714  93.142857 138.285714  26.238567 185.571429 
## attr(,"scaled:scale")
##       vyska        vaha         vek         bmi    vyska_cm 
##   0.2243403  34.4936157 287.9720555   2.9824947  22.4340303
scale(lide[,numericke],                                # použijme jiné
      center = apply(lide[,numericke], 2, median),     # vlastní odhad centrální hodnoty
      scale = apply(lide[,numericke], 2, IQR))         # vlastní odhad
##                vyska       vaha         vek         bmi   vyska_cm
## Aleš       0.1111111  0.4150943  0.40000000  1.32130718  0.1111111
## Barbora   -0.1111111 -0.4905660 -0.60000000 -0.82591792 -0.1111111
## Ctirad    -0.7222222 -0.6415094  0.00000000 -0.26619310 -0.7222222
## Drahomíra  0.0000000  0.0000000  1.40000000  0.37856103  0.0000000
## Evžen      1.1111111  0.5660377 -0.06666667 -0.03393869  1.1111111
## Františka -0.6666667 -0.5283019 -0.13333333  0.00000000 -0.6666667
## Goliáš     2.8333333  3.0943396 50.93333333  2.12867695  2.8333333
## attr(,"scaled:center")
##    vyska     vaha      vek      bmi vyska_cm 
##   1.7900  84.0000  27.0000  25.0995 179.0000 
## attr(,"scaled:scale")
##     vyska      vaha       vek       bmi  vyska_cm 
##  0.180000 26.500000 15.000000  2.950406 18.000000
lide_scaled <- scale(lide[-golias,numericke])
apply(lide_scaled, 2, mean)
##         vyska          vaha           vek           bmi      vyska_cm 
## -6.175616e-16  0.000000e+00 -3.235440e-17  9.260894e-18  7.794691e-16
apply(lide_scaled, 2, sd)
##    vyska     vaha      vek      bmi vyska_cm 
##        1        1        1        1        1
# Zde vidíme příklad, kdy je výsledná matice je vybavena dodatečnými atributy
# Ty lze extrahovat pomocí funkce attr() a udáním jména chtěného atributu 
attr(lide_scaled, "scaled:center")  # původní průměry použité pro centrování
##      vyska       vaha        vek        bmi   vyska_cm 
##   1.781667  81.000000  29.500000  25.381668 178.166667
attr(lide_scaled, "scaled:scale")   # původní sm. odchylky použité pro centrování
##      vyska       vaha        vek        bmi   vyska_cm 
##  0.1197358 13.7549991 10.2518291  2.1228304 11.9735820

Pro kategoriální proměnné jsme již viděli, že je vhodné používat tabulky:

kategorialni <- which(sapply(1:ncol(lide), function(j){is.factor(lide[,j])}))
summary(lide[,kategorialni])          # každá veličina marginálně
##  pohlavi     obezita       fbmi   nad30  
##  Muž :4   Norma  :3   Norma  :3   <30:4  
##  Žena:3   Obezita:4   Obezita:4   30+:3
table(lide[,kategorialni])            # sdružené rozdělení všech zadaných
## , , fbmi = Norma, nad30 = <30
## 
##        obezita
## pohlavi Norma Obezita
##    Muž      2       0
##    Žena     1       0
## 
## , , fbmi = Obezita, nad30 = <30
## 
##        obezita
## pohlavi Norma Obezita
##    Muž      0       0
##    Žena     0       1
## 
## , , fbmi = Norma, nad30 = 30+
## 
##        obezita
## pohlavi Norma Obezita
##    Muž      0       0
##    Žena     0       0
## 
## , , fbmi = Obezita, nad30 = 30+
## 
##        obezita
## pohlavi Norma Obezita
##    Muž      0       2
##    Žena     0       1
apply(lide[,kategorialni], 2, table)  # marginálně pomocí table do jedné tabulky
##      pohlavi obezita fbmi nad30
## [1,]       4       3    3     4
## [2,]       3       4    4     3
apply(lide[,kategorialni], 2, function(sloupec){prop.table(table(sloupec))})  # tabulka proporcí
##        pohlavi   obezita      fbmi     nad30
## [1,] 0.5714286 0.4285714 0.4285714 0.5714286
## [2,] 0.4285714 0.5714286 0.5714286 0.4285714
apply(lide[,kategorialni], 2, table) / nrow(lide)  # taky tabulka proporcí
##        pohlavi   obezita      fbmi     nad30
## [1,] 0.5714286 0.4285714 0.4285714 0.5714286
## [2,] 0.4285714 0.5714286 0.5714286 0.4285714

Doteď jsme spíše hleděli na marginální rozdělení veličin, přičemž vztahy mezi proměnnými byly zanedbávány. Statistické problémy jsou ale často mířeny na to odhalit případné závislosti. Každá analýza dat tak začíná zevrubnou explorační analýzou, abychom dostali představu o základních souvislostech (a pak použili vhodný model). Analýzu musíme uzpůsobit jednotlivým typům proměnných

Pro dvě numerické proměnné můžeme napočítat různé míry závislostí:

# raději bez Goliáše, který odhady vychyluje
cor(lide[-golias,numericke])                        # Pearsonův korelační koeficient (míra lineární závislosti)
##               vyska      vaha        vek       bmi   vyska_cm
## vyska    1.00000000 0.8767636 0.07576306 0.1753761 1.00000000
## vaha     0.87676364 1.0000000 0.34181028 0.6266473 0.87676364
## vek      0.07576306 0.3418103 1.00000000 0.5940773 0.07576306
## bmi      0.17537615 0.6266473 0.59407732 1.0000000 0.17537615
## vyska_cm 1.00000000 0.8767636 0.07576306 0.1753761 1.00000000
cor(lide[-golias,numericke], method = "kendall")    # Kendallovo tau (založeno na pořadí)
##               vyska       vaha        vek       bmi   vyska_cm
## vyska    1.00000000 1.00000000 0.06666667 0.3333333 1.00000000
## vaha     1.00000000 1.00000000 0.06666667 0.3333333 1.00000000
## vek      0.06666667 0.06666667 1.00000000 0.4666667 0.06666667
## bmi      0.33333333 0.33333333 0.46666667 1.0000000 0.33333333
## vyska_cm 1.00000000 1.00000000 0.06666667 0.3333333 1.00000000
cor(lide[-golias,numericke], method = "spearman")   # Spearmanův korelační koeficient (založeno na pořadí)
##              vyska      vaha       vek       bmi  vyska_cm
## vyska    1.0000000 1.0000000 0.2571429 0.4285714 1.0000000
## vaha     1.0000000 1.0000000 0.2571429 0.4285714 1.0000000
## vek      0.2571429 0.2571429 1.0000000 0.7142857 0.2571429
## bmi      0.4285714 0.4285714 0.7142857 1.0000000 0.4285714
## vyska_cm 1.0000000 1.0000000 0.2571429 0.4285714 1.0000000

Pro vztah numerické a kategoriální je nejlépe porovnávat charakteristiky v jednotlivých podskupinách. K tomu je velmi užitečná funkce tapply():

with(lide[-golias,], tapply(bmi, pohlavi, mean))     # průměr pro různá pohlaví
##      Muž     Žena 
## 26.10380 24.65954
with(lide[-golias,], tapply(bmi, pohlavi, sd))       # směrodatná odchylka
##      Muž     Žena 
## 2.529673 1.817243
with(lide[-golias,], tapply(bmi, pohlavi, summary))  # přehled několika popisných charakteristik
## $Muž
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   24.31   24.66   25.00   26.10   27.00   29.00 
## 
## $Žena
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   22.66   23.88   25.10   24.66   25.66   26.22
tapply(lide$vaha, lide$obezita, summary)
## $Norma
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      67      69      71      79      85      99 
## 
## $Obezita
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    70.0    80.5    89.5   103.8   112.8   166.0
tapply(lide$vyska, lide$pohlavi, quantile, probs = seq(0, 1, by = 0.1)) # decily
## $Muž
##    0%   10%   20%   30%   40%   50%   60%   70%   80%   90%  100% 
## 1.660 1.705 1.750 1.795 1.846 1.900 1.954 2.021 2.114 2.207 2.300 
## 
## $Žena
##    0%   10%   20%   30%   40%   50%   60%   70%   80%   90%  100% 
## 1.670 1.690 1.710 1.730 1.750 1.770 1.774 1.778 1.782 1.786 1.790

Pro vztahy mezi kategoriálními veličinami je opět nejlepší používat (proporční) tabulky, ovšem je možnost používat proporce nejen přes všechny buňky, ale i buď přes sloupce či přes řádky:

(TAB <- table(lide$fbmi, lide$pohlavi))         # tabulka sdruženého rozdělení
##          
##           Muž Žena
##   Norma     2    1
##   Obezita   2    2
prop.table(TAB)                                 # sdružené proporce, tj. TAB / nrow(lide)
##          
##                 Muž      Žena
##   Norma   0.2857143 0.1428571
##   Obezita 0.2857143 0.2857143
prop.table(TAB, margin = 1)                     # v řádku se vysčítává na 1 (odhad P(pohlavi | fbmi))
##          
##                 Muž      Žena
##   Norma   0.6666667 0.3333333
##   Obezita 0.5000000 0.5000000
# pokud nezávislé, tak by mezi řádky neměl být rozdíl
prop.table(TAB, margin = 2)                     # ve sloupci se vysčítává na 1 (odhad P(fbmi | pohlavi)) 
##          
##                 Muž      Žena
##   Norma   0.5000000 0.3333333
##   Obezita 0.5000000 0.6666667
# pokud nezávislé, tak by mezi sloupci neměl být rozdíl

Někdy je zapotřebí analýzu provést jen na specificky vymezené podskupině dat. Podívejme se, jakým způsobem lze dělat podmnožiny v Rku:

lide[lide$pohlavi == "Muž", ]               # jen muži
##         jmeno   narozeni vyska pohlavi vaha     presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Aleš     Aleš 1992-03-15  1.81     Muž   95  33.58499 days  33 28.99789      181 Obezita Obezita   30+
## Ctirad Ctirad 1998-07-07  1.66     Muž   67  27.27424 days  27 24.31412      166   Norma   Norma   <30
## Evžen   Evžen 1999-09-09  1.99     Muž   99  26.09970 days  26 24.99937      199   Norma   Norma   <30
## Goliáš Goliáš 1234-02-02  2.30     Muž  166 791.68218 days 791 31.37996      230 Obezita Obezita   30+
lide[lide$pohlavi == "Žena", ]              # jen ženy
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Drahomíra Drahomíra 1977-05-31  1.79    Žena   84 48.37486 days  48 26.21641      179 Obezita Obezita   30+
## Františka Františka 2000-01-01  1.67    Žena   70 25.78759 days  25 25.09950      167 Obezita Obezita   <30
lide[(18 <= lide$vek) & (lide$vek <= 40), ] # lidé ve věkovém rozpětí 18-40 let
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Aleš           Aleš 1992-03-15  1.81     Muž   95 33.58499 days  33 28.99789      181 Obezita Obezita   30+
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Ctirad       Ctirad 1998-07-07  1.66     Muž   67 27.27424 days  27 24.31412      166   Norma   Norma   <30
## Evžen         Evžen 1999-09-09  1.99     Muž   99 26.09970 days  26 24.99937      199   Norma   Norma   <30
## Františka Františka 2000-01-01  1.67    Žena   70 25.78759 days  25 25.09950      167 Obezita Obezita   <30
lide$separuj <- (18 <= lide$vek) & (lide$vek <= 40)
subset(lide, subset = separuj, select = numericke)    # použití funkce subset()
##           vyska vaha vek      bmi vyska_cm
## Aleš       1.81   95  33 28.99789      181
## Barbora    1.77   71  18 22.66271      177
## Ctirad     1.66   67  27 24.31412      166
## Evžen      1.99   99  26 24.99937      199
## Františka  1.67   70  25 25.09950      167
lide[lide$separuj, numericke]                         # to samé
##           vyska vaha vek      bmi vyska_cm
## Aleš       1.81   95  33 28.99789      181
## Barbora    1.77   71  18 22.66271      177
## Ctirad     1.66   67  27 24.31412      166
## Evžen      1.99   99  26 24.99937      199
## Františka  1.67   70  25 25.09950      167
lide[lide$separuj, "vyska"]                           # vrací vektor
## [1] 1.81 1.77 1.66 1.99 1.67
lide$vyska[lide$separuj]                              # to samé
## [1] 1.81 1.77 1.66 1.99 1.67
lide[lide$separuj, "vyska", drop = F]                 # zachování data.framu
##           vyska
## Aleš       1.81
## Barbora    1.77
## Ctirad     1.66
## Evžen      1.99
## Františka  1.67
# Je jedno, zda se používá grepl (T/F) či grep (čísla) pro výběr řádků
lide[grepl("^[B-D]", lide$jmeno), ]                   # lidé začínající na písmena B, C, D
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Ctirad       Ctirad 1998-07-07  1.66     Muž   67 27.27424 days  27 24.31412      166   Norma   Norma   <30
## Drahomíra Drahomíra 1977-05-31  1.79    Žena   84 48.37486 days  48 26.21641      179 Obezita Obezita   30+
##           separuj
## Barbora      TRUE
## Ctirad       TRUE
## Drahomíra   FALSE
lide[grep("a$", lide$jmeno), ]                        # lidé se jménem končícím na a
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Drahomíra Drahomíra 1977-05-31  1.79    Žena   84 48.37486 days  48 26.21641      179 Obezita Obezita   30+
## Františka Františka 2000-01-01  1.67    Žena   70 25.78759 days  25 25.09950      167 Obezita Obezita   <30
##           separuj
## Barbora      TRUE
## Drahomíra   FALSE
## Františka    TRUE
lide[is.element(lide$jmeno, c("Evžen", "David")), ]   # jen řádky se jménem z vybrané množiny jmen
##       jmeno   narozeni vyska pohlavi vaha   presny_vek vek      bmi vyska_cm obezita  fbmi nad30 separuj
## Evžen Evžen 1999-09-09  1.99     Muž   99 26.0997 days  26 24.99937      199   Norma Norma   <30    TRUE
lide[lide$jmeno == c("Evžen", "David"), ]             # to samé, ale trochu protestuje
## Warning in lide$jmeno == c("Evžen", "David"): longer object length is not a multiple of shorter object length
##       jmeno   narozeni vyska pohlavi vaha   presny_vek vek      bmi vyska_cm obezita  fbmi nad30 separuj
## Evžen Evžen 1999-09-09  1.99     Muž   99 26.0997 days  26 24.99937      199   Norma Norma   <30    TRUE
lide[lide$jmeno %in% c("Evžen", "David"), ]           # to samé, bezpečněji bez warningu
##       jmeno   narozeni vyska pohlavi vaha   presny_vek vek      bmi vyska_cm obezita  fbmi nad30 separuj
## Evžen Evžen 1999-09-09  1.99     Muž   99 26.0997 days  26 24.99937      199   Norma Norma   <30    TRUE

Občas máme v datech přítomné hodnoty NA (tedy vlastně hodnoty nepřítomné). Toto jsou základní funkce, které nám pomáhají se s nimi poprat:

lide[c("Drahomíra", "Goliáš"), "vek"] <- NA
lide["Evžen", "vaha"] <- NA
summary(lide[, numericke])            # automaticky ignoruje chybějící pozorování
##      vyska            vaha             vek            bmi           vyska_cm    
##  Min.   :1.660   Min.   : 67.00   Min.   :18.0   Min.   :22.66   Min.   :166.0  
##  1st Qu.:1.720   1st Qu.: 70.25   1st Qu.:25.0   1st Qu.:24.66   1st Qu.:172.0  
##  Median :1.790   Median : 77.50   Median :26.0   Median :25.10   Median :179.0  
##  Mean   :1.856   Mean   : 92.17   Mean   :25.8   Mean   :26.24   Mean   :185.6  
##  3rd Qu.:1.900   3rd Qu.: 92.25   3rd Qu.:27.0   3rd Qu.:27.61   3rd Qu.:190.0  
##  Max.   :2.300   Max.   :166.00   Max.   :33.0   Max.   :31.38   Max.   :230.0  
##                  NA's   :1        NA's   :2
apply(lide[, numericke], 2, mean)     # automaticky NEignoruje... kdo si to má pamatovat, že...
##      vyska       vaha        vek        bmi   vyska_cm 
##   1.855714         NA         NA  26.238567 185.571429
apply(lide[, numericke], 2, mean, na.rm = TRUE) # odstran z každého sloupce chybějící pozorování (průměr přes jiný počet pozorování)
##      vyska       vaha        vek        bmi   vyska_cm 
##   1.855714  92.166667  25.800000  26.238567 185.571429
apply(lide[, numericke], 2, function(x){sum(is.na(x))}) # počet NA v jednotlivých sloupcích
##    vyska     vaha      vek      bmi vyska_cm 
##        0        1        2        0        0
apply(lide[, numericke], 1, function(x){sum(is.na(x))}) # počet NA v jednotlivých řádcích
##      Aleš   Barbora    Ctirad Drahomíra     Evžen Františka    Goliáš 
##         0         0         0         1         1         0         1
colSums(is.na(lide[, numericke]))                       # alternativní výpočet
##    vyska     vaha      vek      bmi vyska_cm 
##        0        1        2        0        0
rowSums(is.na(lide[, numericke]))                       # alternativní výpočet
##      Aleš   Barbora    Ctirad Drahomíra     Evžen Františka    Goliáš 
##         0         0         0         1         1         0         1
complete.cases(lide)                                    # které řádky obsahují všechna pozorování
## [1]  TRUE  TRUE  TRUE FALSE FALSE  TRUE FALSE
lide_kompletni <- lide[complete.cases(lide), ]          # omezení jen na řádky se všemi pozorováními
na.omit(lide)                                           # to samé pomocí funkce na.omit
##               jmeno   narozeni vyska pohlavi vaha    presny_vek vek      bmi vyska_cm obezita    fbmi nad30
## Aleš           Aleš 1992-03-15  1.81     Muž   95 33.58499 days  33 28.99789      181 Obezita Obezita   30+
## Barbora     Barbora 2006-12-01  1.77    Žena   71 18.87178 days  18 22.66271      177   Norma   Norma   <30
## Ctirad       Ctirad 1998-07-07  1.66     Muž   67 27.27424 days  27 24.31412      166   Norma   Norma   <30
## Františka Františka 2000-01-01  1.67    Žena   70 25.78759 days  25 25.09950      167 Obezita Obezita   <30
##           separuj
## Aleš         TRUE
## Barbora      TRUE
## Ctirad       TRUE
## Františka    TRUE
# Pro výpočet korelací potřebujeme vždy plný pár, abychom se vyhnuli NA hodnotám
cor(lide[, numericke])                                  # hodně NA
##              vyska vaha vek       bmi  vyska_cm
## vyska    1.0000000   NA  NA 0.7193414 1.0000000
## vaha            NA    1  NA        NA        NA
## vek             NA   NA   1        NA        NA
## bmi      0.7193414   NA  NA 1.0000000 0.7193414
## vyska_cm 1.0000000   NA  NA 0.7193414 1.0000000
cor(lide[, numericke], use = "complete.obs")            # používá jen řádky s kompletními pozorováními
##              vyska      vaha       vek       bmi  vyska_cm
## vyska    1.0000000 0.8017758 0.1654597 0.4539997 1.0000000
## vaha     0.8017758 1.0000000 0.7067363 0.8963661 0.8017758
## vek      0.1654597 0.7067363 1.0000000 0.9264998 0.1654597
## bmi      0.4539997 0.8963661 0.9264998 1.0000000 0.4539997
## vyska_cm 1.0000000 0.8017758 0.1654597 0.4539997 1.0000000
cor(lide[, numericke], use = "pairwise.complete.obs")   # kompletní pozorování, ale vždy po párech proměnných
##               vyska      vaha        vek       bmi   vyska_cm
## vyska    1.00000000 0.9867680 0.09766312 0.7193414 1.00000000
## vaha     0.98676804 1.0000000 0.70673630 0.8874009 0.98676804
## vek      0.09766312 0.7067363 1.00000000 0.9239810 0.09766312
## bmi      0.71934140 0.8874009 0.92398096 1.0000000 0.71934140
## vyska_cm 1.00000000 0.9867680 0.09766312 0.7193414 1.00000000

Explorace pomocí čísel a tabulek je sice důležitá, ale daleko ilustrativnější bývají obrázky. Těm se budeme důkladně věnovat v dalším cvičení. Ale ukážeme si tady jednu užitečnou funkci pro konverzi tabulek do TeXu:

library(stargazer)
## 
## Please cite as:
##  Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.
##  R package version 5.2.3. https://CRAN.R-project.org/package=stargazer
stargazer(lide[,numericke])
stargazer(lide[,numericke], summary = F)
stargazer(lide[,numericke], mean.sd = F, median = T, iqr = T)
stargazer(lide[,numericke], decimal.mark = ",")
stargazer(lm(vyska ~ vaha,  data = lide))

Má však tolik parametrů, že je obtížné se v tom vyznat. Těžko se pak dá přizpůsobit, aby výsledek odpovídal Vaší představě. Užitečné pro rychlé výstupy bez nutnosti hezkého formátování (např. domácí úlohy). Ale pro bakalářku či diplomku bych doporučoval sepsat si tabulku manuálně (viz cvičení 5).

Jak importovat a exportovat data do/z Rka

Spousta datasetů pro edukativní účely je již přístupna přímo v Rku a balíčcích.

data(iris)                       # přístupné v základní instalaci
# help(iris)
head(iris)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
data(Boston, package = "MASS")   # takto se zpřístupní z konkrétního balíčku
# help(Boston)
head(Boston)
##      crim zn indus chas   nox    rm  age    dis rad tax ptratio  black lstat medv
## 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98 24.0
## 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14 21.6
## 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03 34.7
## 4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94 33.4
## 5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33 36.2
## 6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21 28.7

Ale při práci na reálných problémech je třeba umět importovat vlastní dataset. Z formátu .RData, tedy ve formátu určeném pro Rko, už data načítat umíme pomocí load:

# Nastavení adresářů
WD <- getwd()
dir_data <- file.path(dirname(WD), "data")                # upravte si dle vlastního adresáře
dir_domaci <- file.path(dirname(WD), "domaci")            # upravte si dle vlastního adresáře

save(lide, file = file.path(dir_data, "lide.RData"))
load(file.path(dir_data, "lide.RData"))

Ale nejčastěji máme data uložená v jiných formátech jako csv či xlsx. Obecně nejjednodušší způsob načítání jediného datasetu je v záložce File > Import Dataset, kde si lze vybrat ze spousty možných formátů a Rstudio Vás již navede, dokonce zobrazí náhled dat. Lze si nastavit kolik řádků přeskočit, kolik maximálně načíst řádků, který řádek obsahuje názvy sloupců, co je desetinné znaménko, jaké všechny symboly znamenají NA, jak jsou odděleny buňky apod. V pravo dole také zobrazí, jakým příkazem docílíte načtení dat. Doporučuji zkopírovat a vložit do skriptu na příslušné místo (typicky na začátku).

Čistě technicky se tak obejdete bez znalosti těch funkcí. Ovšem jsou případy, kdy je třeba nahrát desítky datasetů podobného formátu. Automatizace pomocí skriptového kódu a tedy znalost funkcí se může hodit:

# Načtení dat přímo z Vaší složky:
data <- read.csv(file = file.path(dir_domaci, "default_of_credit_card_clients.csv"))
# defaultní hodnoty: header = T, sep = ",", quote = "\"", dec = ".", fill = TRUE, comment.char = "", ...
# Funkce read.csv2 je přednastavená na "české" poměry:
# read.csv2(file, header = TRUE, sep = ";", quote = "\"", dec = ",", fill = TRUE, comment.char = "", ...)
head(data)
##    X        X1  X2        X3       X4  X5    X6    X7    X8    X9   X10   X11       X12       X13       X14
## 1 ID LIMIT_BAL SEX EDUCATION MARRIAGE AGE PAY_0 PAY_2 PAY_3 PAY_4 PAY_5 PAY_6 BILL_AMT1 BILL_AMT2 BILL_AMT3
## 2  1     20000   2         2        1  24     2     2    -1    -1    -2    -2      3913      3102       689
## 3  2    120000   2         2        2  26    -1     2     0     0     0     2      2682      1725      2682
## 4  3     90000   2         2        2  34     0     0     0     0     0     0     29239     14027     13559
## 5  4     50000   2         2        1  37     0     0     0     0     0     0     46990     48233     49291
## 6  5     50000   1         2        1  57    -1     0    -1     0     0     0      8617      5670     35835
##         X15       X16       X17      X18      X19      X20      X21      X22      X23
## 1 BILL_AMT4 BILL_AMT5 BILL_AMT6 PAY_AMT1 PAY_AMT2 PAY_AMT3 PAY_AMT4 PAY_AMT5 PAY_AMT6
## 2         0         0         0        0      689        0        0        0        0
## 3      3272      3455      3261        0     1000     1000     1000        0     2000
## 4     14331     14948     15549     1518     1500     1000     1000     1000     5000
## 5     28314     28959     29547     2000     2019     1200     1100     1069     1000
## 6     20940     19146     19131     2000    36681    10000     9000      689      679
##                            Y
## 1 default payment next month
## 2                          1
## 3                          1
## 4                          0
## 5                          0
## 6                          0
# Načtení dat přímo z webové stránky bez nutnosti stahovat do osobního adresáře:
data <- read.csv("https://www.karlin.mff.cuni.cz/~vavraj/Rko/domaci/default_of_credit_card_clients.csv")

# Stažení souboru pomocí Rka
# download.file("https://www.karlin.mff.cuni.cz/~vavraj/Rko/domaci/default_of_credit_card_clients.xls", 
#               destfile = file.path(dir_domaci, "default_of_credit_card_clients.xls"))

# Načtení z xls souboru:
library(readxl)              # nutná knihovna s funkcí read_excel()
data <- read_excel(file.path(dir_domaci, "default_of_credit_card_clients.xls"), # neumí přímo pomocí URL
                   sheet = "Data", # lze nastavit z jakého listu (sheet) načíst data 
                   skip = 1)       # kolik řádků přeskočit (první jsou názvy X.., druhý konkrétní jména)
# zbytek defaultního nastavení: 
#   range = NULL,          rozsah hodnot, třeba "A1:D1" (bere automaticky všechno)
#   col_names = TRUE,      první řádek bude mít názvy sloupců
#   col_types = NULL,      uhádne si typ sloupců sám
#   na = "",               znak pro chybějící hodnoty
#   trim_ws = TRUE,        odstraňuje přebytečné mezery (white spaces)
#   n_max = Inf            maximální počet řádků k načtení

Ukládání dat lze také provést jediným zavoláním funkce. Jen je třeba si ohlídat, aby to bylo uloženo ve formátu, který očekává ten, komu je zašlete.

# Ukládání jako csv
write.table(lide, file = file.path(dir_data, "lide.csv"),
            append = FALSE,                      # zda připsat k již existujícímu souboru se stejným názvem
            sep = " ",                           # symbol oddělující buňky (mezera je zde default)
            na = "NA",                           # jak uložit NA hodnoty 
            dec = ".",                           # desetinné znaménko
            row.names = TRUE,                    # zda uložit i s názvy řádků
            col.names = TRUE,                    # zda uložit i s názvy sloupců
            fileEncoding = "")                   # v jakém kódování uložit
# Alternativně lze použít tyto funkce
# write.csv()    # má nastaveno sep = ",", dec = "."
# write.csv2()   # má nastaveno sep = ";", dec = ","

library("openxlsx")
wb <- createWorkbook()   # vytvoří dokument, lze nastavit: creator, title, subject, category = "někdo, něco"

addWorksheet(wb, "Lidé") # vytvoří záložku (sheet) se jménem "Lidé"
writeDataTable(wb, "Lidé", lide, rowNames = T)

addWorksheet(wb, "Domácí úkol") # vytvoří záložku (sheet) se jménem "Domácí úkol"
writeDataTable(wb, "Domácí úkol", head(data)) # uložení jen prvních pár řádků

saveWorkbook(wb, file = file.path(dir_data, "muj_novy_excel.xlsx"), overwrite = T) # uložení xlsx souboru

loadWorkbook(file = file.path(dir_data, "muj_novy_excel.xlsx"))                    # opětovné načtení souboru
## A Workbook object.
##  
## Worksheets:
##  Sheet 1: "Lidé"
##  
## 
##  Sheet 2: "Domácí úkol"
##  
## 
##  
##  Worksheet write order: 1, 2
##  Active Sheet 1: "Lidé" 
##  Position: 1

Úložky na procvičení

Vyřešte si to sami, aniž byste se dívali do řešení (úplně dole vespod skriptu).

  1. Uvažte následující data.frame:
exam_data = data.frame(
   name = c('Anastasia','Dima','Katherine','James','Emily','Michael','Matthew','Laura','Kevin','Jonas'),
   score = c(12.5, 9, 16.5, 12, 9, 20, 14.5, 13.5, 8, 19),
   attempts = c(1, 3, 2, 3, 2, 3, 1, 1, 2, 1),
   qualify = c('yes', 'no', 'yes', 'no', 'no', 'yes', 'yes', 'no', 'no', 'yes')
)

A proveďte následující operace:

  1. Uvažte následující dva datasety:
df_2A = data.frame(item = c("car", "bike", "scooter"),
                   Jan_sale = c(12, 14, 12),
                   Feb_sale = c(11, 12, 15),
                   Mar_sale = c(12, 14, 15)
)
df_2B = data.frame(item = c("e-bike", "car", "rollerblades"),
                   Jan_sale = c(10, 12, 12),
                   Feb_sale = c(13, 11, 19),
                   Mar_sale = c(17, 12, 22)
)

S pomocí množinových operací nalezněte položky (a dejte do jediného data.framu), které se nacházejí:

  1. Nalezněte v Rku dataset airquality obsahující měření kvality vzduchu v New Yorku z roku 1973.
  1. Nalezněte v Rku dataset iris obsahující měření květů kosatců (v centimetrech).
  1. Seznamte se s datasetem diamonds z balíčku ggplot2.
  1. Vytvořte si vlastní náhodně nagenerovaný dataset. Snažte se být pestří v různých typech proměnných: numerické, binární, kategoriální (ordinální, nominální) atd. Při generování vnořte nějaké závislosti mezi proměnnými. Zavedenou závislost nějak doložte tím, jak se projevila v datech, např. tabulkou hodnot.