Rkový skript ke stažení: R
Co si zde představíme?
data.frame
pro stavbu datasetů,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á
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).
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
Vyřešte si to sami, aniž byste se dívali do řešení (úplně dole vespod skriptu).
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:
data.frame
obsahující pouze sloupce
name
a score
.country
, víte-li, že
všichni jsou z USA.name
a
qualify
.Dima
,
James
, Michael
.score
, v případě shody dle
name
.NA
) hodnoty u
attempts
a lidí Dima
, James
,
Michael
, Laura
.attempts
.attempts
konstantou 3.name
a score
na
stud_name
a stud_score
.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í:
airquality
obsahující měření
kvality vzduchu v New Yorku z roku 1973.data.frame
.NA
hodnoty a vytiskněte to samé
znovu.Ozone
a Solar.R
(jak malé, tak velké) a diskutujte, zda se jedná o outliery.iris
obsahující měření květů
kosatců (v centimetrech).Sepal.Length
a Sepal.Width
.x
pravidelně střídajících se hodnot
1 a 2, každá 75×.x
k iris
a vytvořte nový
dataset irisx
.x
zvlášť.virginica
a
Sepal.Width
větší než 3.5, a to bez posledního
sloupce.diamonds
z balíčku
ggplot2
.SI2
o
hloubce alespoň 70.