# ____________________________________________________________________________ # Transformace dat - pokračování #### library(tidyverse) library(nycflights13) # * Použití pipe operátoru ----------------------------------- # Přehledné zřetězení více operací dohromady flights |> filter(dest == "IAH") |> mutate(speed = distance / air_time * 60) |> select(year:day, dep_time, carrier, flight, speed) |> arrange(desc(speed)) # Bez něj by kód vypadat nějak takto arrange( select( mutate( filter( flights, dest == "IAH" ), speed = distance / air_time * 60 ), year:day, dep_time, carrier, flight, speed ), desc(speed) ) # Nebo bychom museli vytvářet mnoho nových objektů flights1 <- filter(flights, dest == "IAH") flights2 <- mutate(flights1, speed = distance / air_time * 60) flights3 <- select(flights2, year:day, dep_time, carrier, flight, speed) arrange(flights3, desc(speed)) # * Rozdělení datasetu do skupin -------------------------------------------- # Funkce group_by() rozdělí dataset do skupin pro další analýzu # Všimněte si výstupu groups flights |> group_by(month) # V kombinaci s funkcí summarise() můžeme vypočíst různé statistiky # Třeba průměrné zpoždění při odletu # Chybějící hodnoty jsou "nakažlivé" flights |> group_by(month) |> summarise( avg_delay = mean(dep_delay) ) # Arugmentem na.rm je budeme ignorovat flights |> group_by(month) |> summarise( avg_delay = mean(dep_delay, na.rm = TRUE) ) # Funkce n() podá informace o počtu řádků flights |> group_by(month) |> summarise( avg_delay = mean(dep_delay, na.rm = TRUE), n = n() ) # Funkce slice_ grouped <- flights %>% group_by(month) # slice_head() Vybere první řádek/řádky z každé skupiny grouped %>% slice_head(n = 1) # slice_tail() Vybere poslední řádek/řádky z každé skupiny grouped %>% slice_tail(n = 1) # slice_min() vybere řádek/řádky s nejmenšími hodnotami zvoleného sloupce grouped %>% slice_min(dep_delay, n = 1) # slice_max() Vybere řádek/řádky s největšími hodnotami zvoleného sloupce grouped %>% slice_max(arr_delay, n = 1) # slice_sample() vybere náhodné řádky grouped %>% slice_sample(n = 1) # Do funkce group_by můžeme dát více proměnných daily <- flights |> group_by(year, month, day) daily daily %>% summarise( avg_daily_delay = mean(dep_delay, na.rm = TRUE) ) # Všimněte si, že funkce summarise() defaultně "odloupne" dělení podle # poslední proměnné (ve výsledném datasetu) # Toto chování lze změnit pomocí argumentu .groups ?summarise # Zrušit rozdělení do skupin jde pomocí funkce ungroup daily %>% ungroup() %>% summarise( avg_total_delay = mean(dep_delay, na.rm = TRUE) ) # Nověji jde pracovat i bez funkce group_by() a specifikovat rozdělení # datasetu do skupin až v samotné funkci summarise() # pomocí argumentu .by flights |> summarise( delay = mean(dep_delay, na.rm = TRUE), n = n(), .by = c(origin, dest) ) # ____________________________________________________________________________ # Import dat #### # * Flat files ------------------------------------------------------------- # Funkce balíčku readr (spadá pod tidyverse) # funkce read_csv() čte data, kde je oddělovačem hodnot čárka # funkce read_csv2() čte data, kde je oddělovačem hodnot středník # funkce read_tsv() čte data, kde je oddělovačem hodnot tabulátor # funkce read_delim() je obecná funkce, která umožňuje specifikovat jakýkoli # oddělovat hodnot students <- read_csv("https://pos.it/r4ds-students-csv") # Dataset se nám importoval, ale nevypadá úplně OK students # Nejdříve můžeme redefinovat chybějící hodnoty students <- read_csv("https://pos.it/r4ds-students-csv", na = c("", "N/A")) students # Můžeme také změnit názvy sloupců, ať jsou konzistentní a lépe se na ně # odkazuje students |> rename( student_id = `Student ID`, full_name = `Full Name` ) # Automatizovaně s využitím balíčku janitor a funkce clean_names() students <- students |> janitor::clean_names() students # Dále můžeme opravit sloupec age students %>% mutate(age = if_else(age == "five", true = "5", false = age)) students %>% mutate(age = if_else(age == "five", true = "5", false = age) %>% as.integer()) students <- students %>% mutate(age = if_else(age == "five", true = "5", false = age) %>% as.integer()) # Nakonec můžeme meal_plan změnit na kategorickou proměnnou summary(students) students <- students %>% mutate( meal_plan = factor(meal_plan) ) summary(students) # Balíček readr většinou dovede správně identifikovat typ sloupců # Mohli bychom například mít tento .csv soubor example <- " logical,numeric,date,string TRUE,1,2021-01-15,abc false,4.5,2021-02-15,def T,Inf,2021-02-16,ghi " # Načteno ok read_csv(example) # Někdy je nutné ručně definovat chybějící hodnoty simple_csv <- " x 10 . 20 30" read_csv(simple_csv) read_csv(simple_csv, na = ".") # Nebo ručně specifikovat, jaký typ proměnné chceme, pomocí argumentu col_types df <- read_csv( simple_csv, col_types = list(x = col_double()) ) # A pak se pomocí funkce problems() podívat, jestli při importu nastal problém problems(df) # Různé typy sloupců k nastavení # col_logical(): logické hodnoty 0/1, TRUE/FALSE # col_integer(): celá čísla # col_double(): reálná čísla # col_character(): text # col_factor(): kategorické proměnné # col_date(): datum # col_datetime(): datum a čas # col_number(): z "textu" importuje pouze numerické hodnoty # col_skip(): sloupec není importován, ale "přeskočen" # Další cvičný csv soubor another_csv <- " x,y,z 1,2,3 4,5,6" # Taky můžeme změnit defaultní typ sloupců, např. kdybychom pro jistotu # chtěli nejprve vše nejprve importovat jako text read_csv( another_csv, col_types = cols(.default = col_character()) ) # Anebo můžeme ručně definovat, že se mají importovat pouze určité sloupce # Takto bychom specifikovali, že se sloupec x má importovat jako textový # (ostatní sloupce automaticky) read_csv( another_csv, col_types = list(x = col_character()) ) # Takto bychom specifikovali, že se sloupec x má importovat jako textový # a že jiné se importovat nemají read_csv( another_csv, col_types = cols_only(x = col_character()) ) # * SPSS ----------------------------------------------------------------- # Balíček haven library(haven) # Načtení dat z SPSS obvykle není problematické international <- read_spss("data/international.sav") international # Jediné, co nám nemusí vyhovovat, je to, že se proměnné definované # v SPSS jako nominální a ordinální importují jako numerické # ale labely jsou zachovány # Ale balíček haven proto má pomocnou funkci as_factor ?as_factor international %>% mutate( contint = as_factor(contint) ) # * Excel -------------------------------------------------------------- # Spíše případová studie library(readxl) library(janitor) df <- read_excel("data/four_countries_data.xlsx") # Takhle bychom to nechtěli df # Nejprve opravíme názvy proměnných a někam si je uložíme var_names <- read_excel("data/four_countries_data.xlsx", n_max = 0) %>% clean_names() %>% colnames() var_names # Na druhém řádku jsou popisnější labely proměnných, ty si také uložíme var_labels <- read_excel("data/four_countries_data.xlsx", skip = 1, n_max = 0) %>% colnames() metadata <- tibble( names = var_names, labels = var_labels ) # Pak konečně importujeme dataset bez tří prvních řádků df <- read_excel("data/four_countries_data.xlsx", skip = 3, col_names = FALSE) df # Pomocí set_names() přepíšeme názvy sloupců df <- df %>% set_names(var_names) df # Dále můžeme odstranit některé nepotřebné sloupce # s využitím funkcí balíčku janitor df <- df %>% remove_constant() %>% remove_empty(which = "cols") df # Někdy se z Excelu importuje chybně datum jako numerická proměnná # (počet dní od data 1899-12-30) # I pro to má janitor užitečnou funkci df <- df %>% mutate(start_date = excel_numeric_to_date(start_date), end_date = excel_numeric_to_date(end_date), recorded_date = excel_numeric_to_date(recorded_date)) df