Статистички софтвер 1: Обрада података са dplyr пакетом

Стефан Малбашић, Математички факултет, Универзитет у Београду

Пакет dplyr

За рад са базама података користићемо пакет dplyr.

install.packages("dplyr")
library(dplyr)

Користићемо базу flights из пакета nycflights13 да илуструјемо рад са подацима коришћењем наведеног пакета. Ова база садржи податке о свих 336.776 летова из Њујорка у току 2013. године (информације о бази можете погледати са ?nycflights13::flights).

(df_nyc = nycflights13::flights)
## # A tibble: 336,776 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 336,766 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

Примећујемо да је мало другачији приказ података од оног на који смо навикли у досадашњем раду са базама података (да бисмо видели целу базу, можемо покренути View(flights), што ће приказати базу у засебном прозору). Приказује се другачије јер је у питању tibble формат за табеларне податке. Можемо прећи са data.frame на овај прегледнији формат коришћењем функције as_tibble:

(df = data.frame(x = c(1, 2, 3), y = c(0.1, 0.5, 0.6), z = c("a", "b", "c")))
##   x   y z
## 1 1 0.1 a
## 2 2 0.5 b
## 3 3 0.6 c
as_tibble(df)
## # A tibble: 3 × 3
##       x     y z    
##   <dbl> <dbl> <chr>
## 1     1   0.1 a    
## 2     2   0.5 b    
## 3     3   0.6 c

Примећујемо скраћенице од три (или четири) слова испод назива сваке колоне. Оне описују тип променљиве:

  • int целобројни тип података;

  • dbl реални бројеви;

  • chr низови карактера;

  • dttm датум и време;

  • lgl логички тип, за векторе који садрже само TRUE или FALSE;

  • fctr фактори, које R користи за представљање категоричких променљивих са фиксним могућим вредностима;

Основне функције

Научићемо да користимо пет основних функција које нам омогућавају да решимо већину проблема у манипулацији подацима:

  • filter() - избор опсервација (редова) на основу задатих условa;

  • arrange() - сортирање редова;

  • select(), rename() - избор променљивих (колона) помоћу њихових имена;

  • mutate(), transmute() - креирање нових промењивих у функцији од постојећих;

  • summarise() - рачунање сумарних вредности.

Све ове функције раде на сличан начин - први аргумент је база са којом радимо, а додатним аргументима описујемо шта желимо да радимо са базом, користећи имена променљивих тј. колона (без $). Резултат је нова база података.

Такође, често могу бити корисне и функције sample_n() и sample_frac(), које служе за узимање случајног узорка редова: sample_n() користимо када желимо одређени број редова, а sample_frac() када желимо одређени проценат.

sample_n(df_nyc, 10)
## # A tibble: 10 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     4    25     1429           1429         0     1812           1743
##  2  2013     5    27     2058           2100        -2     2237           2253
##  3  2013     3    23     1807           1810        -3     2133           2130
##  4  2013     6    28     1354           1400        -6     1520           1508
##  5  2013    11    30      700            700         0     1033           1023
##  6  2013     4     9     1312           1317        -5     1637           1710
##  7  2013     9     8     2029           2029         0     2236           2248
##  8  2013     5    13     1653           1700        -7     1759           1821
##  9  2013     4     9      749            755        -6      921            920
## 10  2013    11     5     1812           1800        12     1935           1944
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>
sample_frac(df_nyc, 0.01)
## # A tibble: 3,368 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013    10    16      739            749       -10     1020           1043
##  2  2013     1    25      830            830         0     1113           1146
##  3  2013     7    17     1936           1935         1     2253           2223
##  4  2013     4     9      854            900        -6     1212           1216
##  5  2013     1    10     1700           1705        -5     1950           2010
##  6  2013    10    20     1704           1700         4     1958           2010
##  7  2013     6    21     1637           1550        47     1840           1805
##  8  2013     1    11     2141           1800       221       20           2015
##  9  2013     2     5      607            600         7      731            716
## 10  2013     1     4      858            900        -2     1215           1227
## # ℹ 3,358 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

Филтрирање редова помоћу функције filter()

Функција filter() омогућава да правимо подскупове опсервација на основу задатих услова. Први аргумент је име базе са којом радимо. Остали аргументи односе се на променљиве унутар базе података: изразом задајемо услове и бирамо редове где је вредност израза TRUE. На пример, желимо да изаберемо све летове реализоване 1. јануара:

filter(df_nyc, day == 1, month == 1)
## # A tibble: 842 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 832 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

Када позовемо функцију filter(), dplyr изврши операцију филтрирања и враћа нову базу података. Како dplyr функције не мењају почетну базу, ако желимо да сачувамо резултат, морамо да користимо оператор доделе:

jan_1 = filter(df_nyc, day == 1, month == 1)

Да бисмо ефикасно користили филтрирање, морамо правилно да одаберемо опсервације које желимо користећи операторе поређења: >,>=,<,<=,!= и ==. Ако желимо да издвојимо редове који задовољавају више услова, користићемо оператор & (и), тако да сви услови морају бити испуњени да би ред био укључен у излаз. Слично, можемо правити и друге комбинације услова, користећи и операторе |(или) и !(негација).

Честа почетничка грешка у раду у R-у је коришћење = уместо ==, када тестирамо једнакост. Када се то деси, добићемо информацију о грешци:

filter(df_nyc, month = 1)
# > Error: `month` (`month = 1`) must not be named, do you need `==`?

Следећи код проналази све летове који су реализовани у јануару или фебруару:

filter(df_nyc, month == 1 | month == 2)
## # A tibble: 51,955 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 51,945 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

Претходно можемо урадити и коришћењем оператора %in%. Израз x %in% y за сваку вредност из x гледа да ли се налази у вектору y, и ако је тако, на одговарајућој позицији у резултујућем вектору се налази TRUE, а иначе FALSE. Дакле, можемо писати:

filter(df_nyc, month %in% c(1, 2))
## # A tibble: 51,955 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 51,945 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

NA вредности

Резултат филтрирања коришћењем функције filter() укључује само редове где је услов испуњен (тј. TRUE), а искључује FALSE и NA вредности. Ако желимо да сачувамо NA вредности, морамо то експлицитно навести.

(df = tibble(x = c(1, NA, 3, 5, NA)))
## # A tibble: 5 × 1
##       x
##   <dbl>
## 1     1
## 2    NA
## 3     3
## 4     5
## 5    NA
filter(df, x > 1)
## # A tibble: 2 × 1
##       x
##   <dbl>
## 1     3
## 2     5
filter(df, is.na(x) | x > 1)
## # A tibble: 4 × 1
##       x
##   <dbl>
## 1    NA
## 2     3
## 3     5
## 4    NA

Промена редоследа редова помоћу функције помоћу функције arrange()

Функција arrange() као аргументе узима базу података и скуп имена колона по којима се врши сортирање. Ако наведемо више од једног назива колоне, сортира се редом - по првој наведеној колони, па другој, трећој, итд. Погледајмо пример:

df = tibble(x = c(1, 2, 1, 1, 2, 3, 4, 5, 3, 3),
            y = c("c", "b", "a", "b", "a", "a", "b", "a", "c", "a"))
arrange(df, x)
## # A tibble: 10 × 2
##        x y    
##    <dbl> <chr>
##  1     1 c    
##  2     1 a    
##  3     1 b    
##  4     2 b    
##  5     2 a    
##  6     3 a    
##  7     3 c    
##  8     3 a    
##  9     4 b    
## 10     5 a
arrange(df, x, y)
## # A tibble: 10 × 2
##        x y    
##    <dbl> <chr>
##  1     1 a    
##  2     1 b    
##  3     1 c    
##  4     2 a    
##  5     2 b    
##  6     3 a    
##  7     3 a    
##  8     3 c    
##  9     4 b    
## 10     5 a

Користимо desc() да сортирамо у опадајућем редоследу:

arrange(df, desc(x))
## # A tibble: 10 × 2
##        x y    
##    <dbl> <chr>
##  1     5 a    
##  2     4 b    
##  3     3 a    
##  4     3 c    
##  5     3 a    
##  6     2 b    
##  7     2 a    
##  8     1 c    
##  9     1 a    
## 10     1 b

Сортирамо летове у опадајућем редоследу по кашњењу полетања авиона:

arrange(df_nyc, desc(dep_delay))
## # A tibble: 336,776 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     9      641            900      1301     1242           1530
##  2  2013     6    15     1432           1935      1137     1607           2120
##  3  2013     1    10     1121           1635      1126     1239           1810
##  4  2013     9    20     1139           1845      1014     1457           2210
##  5  2013     7    22      845           1600      1005     1044           1815
##  6  2013     4    10     1100           1900       960     1342           2211
##  7  2013     3    17     2321            810       911      135           1020
##  8  2013     6    27      959           1900       899     1236           2226
##  9  2013     7    22     2257            759       898      121           1026
## 10  2013    12     5      756           1700       896     1058           2020
## # ℹ 336,766 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

NA вредности се увек налазе на крају, било да сортирамо растуће или опадајуће:

df = tibble(x = c(1, NA, 3, 5, NA))
arrange(df, x)
## # A tibble: 5 × 1
##       x
##   <dbl>
## 1     1
## 2     3
## 3     5
## 4    NA
## 5    NA
arrange(df, desc(x))
## # A tibble: 5 × 1
##       x
##   <dbl>
## 1     5
## 2     3
## 3     1
## 4    NA
## 5    NA

Селектовање колона помоћу функције select()

Често базе података садрже велики број променљивих, а од значаја нам је само неколико њих. Функција select() нам омогућава да се фокусирамо на подскуп променљивих који нам је потребан, тако што јој проследимо имена колона које нас интересују.

select(df_nyc, year, month, day)
## # A tibble: 336,776 × 3
##     year month   day
##    <int> <int> <int>
##  1  2013     1     1
##  2  2013     1     1
##  3  2013     1     1
##  4  2013     1     1
##  5  2013     1     1
##  6  2013     1     1
##  7  2013     1     1
##  8  2013     1     1
##  9  2013     1     1
## 10  2013     1     1
## # ℹ 336,766 more rows

Селектујемо све колоне између year и day, укључујући и њих:

select(df_nyc, year:day)
## # A tibble: 336,776 × 3
##     year month   day
##    <int> <int> <int>
##  1  2013     1     1
##  2  2013     1     1
##  3  2013     1     1
##  4  2013     1     1
##  5  2013     1     1
##  6  2013     1     1
##  7  2013     1     1
##  8  2013     1     1
##  9  2013     1     1
## 10  2013     1     1
## # ℹ 336,766 more rows

Селектујемо све колоне осим оних између year и day (искључујући и њих):

select(df_nyc, -(year:day))
## # A tibble: 336,776 × 16
##    dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
##       <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
##  1      517            515         2      830            819        11 UA     
##  2      533            529         4      850            830        20 UA     
##  3      542            540         2      923            850        33 AA     
##  4      544            545        -1     1004           1022       -18 B6     
##  5      554            600        -6      812            837       -25 DL     
##  6      554            558        -4      740            728        12 UA     
##  7      555            600        -5      913            854        19 B6     
##  8      557            600        -3      709            723       -14 EV     
##  9      557            600        -3      838            846        -8 B6     
## 10      558            600        -2      753            745         8 AA     
## # ℹ 336,766 more rows
## # ℹ 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

Постоји неколико помоћних функција које се могу користити у оквиру функције select() (погледајте ?select за више детаља), на пример:

  • starts_with("xyz"): проналази имена колона која почињу са “xyz”;

  • ends_with("xyz"): проналази имена колона која се завршавају са “xyz”;

  • contains("xyz"): проналази имена колона која садрже “xyz”;

select(df_nyc, contains("dep"))
## # A tibble: 336,776 × 3
##    dep_time sched_dep_time dep_delay
##       <int>          <int>     <dbl>
##  1      517            515         2
##  2      533            529         4
##  3      542            540         2
##  4      544            545        -1
##  5      554            600        -6
##  6      554            558        -4
##  7      555            600        -5
##  8      557            600        -3
##  9      557            600        -3
## 10      558            600        -2
## # ℹ 336,766 more rows

Функција select() се може користити и за промену имена колона, али се ретко користи, јер “испушта” све променљиве које нису експлицитно наведене. Уместо ње, користи се функција rename(), која чува и све променљиве које нису експлицитно наведене.

select(df_nyc, time_of_departure = dep_time)
## # A tibble: 336,776 × 1
##    time_of_departure
##                <int>
##  1               517
##  2               533
##  3               542
##  4               544
##  5               554
##  6               554
##  7               555
##  8               557
##  9               557
## 10               558
## # ℹ 336,766 more rows
rename(df_nyc, time_of_departure = dep_time)
## # A tibble: 336,776 × 19
##     year month   day time_of_departure sched_dep_time dep_delay arr_time
##    <int> <int> <int>             <int>          <int>     <dbl>    <int>
##  1  2013     1     1               517            515         2      830
##  2  2013     1     1               533            529         4      850
##  3  2013     1     1               542            540         2      923
##  4  2013     1     1               544            545        -1     1004
##  5  2013     1     1               554            600        -6      812
##  6  2013     1     1               554            558        -4      740
##  7  2013     1     1               555            600        -5      913
##  8  2013     1     1               557            600        -3      709
##  9  2013     1     1               557            600        -3      838
## 10  2013     1     1               558            600        -2      753
## # ℹ 336,766 more rows
## # ℹ 12 more variables: sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
## #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
## #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

Изворна база се не мења када користимо select() и rename().

df_nyc
## # A tibble: 336,776 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 336,766 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

Друга опција је да користимо select() у комбинацији са everything(). Ово је нарочито корисно када имамо неколико променљивих које желимо да преместимо на почетак.

select(df_nyc, time_hour, air_time, everything())
## # A tibble: 336,776 × 19
##    time_hour           air_time  year month   day dep_time sched_dep_time
##    <dttm>                 <dbl> <int> <int> <int>    <int>          <int>
##  1 2013-01-01 05:00:00      227  2013     1     1      517            515
##  2 2013-01-01 05:00:00      227  2013     1     1      533            529
##  3 2013-01-01 05:00:00      160  2013     1     1      542            540
##  4 2013-01-01 05:00:00      183  2013     1     1      544            545
##  5 2013-01-01 06:00:00      116  2013     1     1      554            600
##  6 2013-01-01 05:00:00      150  2013     1     1      554            558
##  7 2013-01-01 06:00:00      158  2013     1     1      555            600
##  8 2013-01-01 06:00:00       53  2013     1     1      557            600
##  9 2013-01-01 06:00:00      140  2013     1     1      557            600
## 10 2013-01-01 06:00:00      138  2013     1     1      558            600
## # ℹ 336,766 more rows
## # ℹ 12 more variables: dep_delay <dbl>, arr_time <int>, sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
## #   dest <chr>, distance <dbl>, hour <dbl>, minute <dbl>

Додавање нових променљивих помоћу функције mutate()

Функција mutate() увек додаје нову колону на крај, па ћемо почети креирањем базе са мањим бројем промењивих како бисмо видели нове променљиве.

(df_nyc_small = select(df_nyc, 
  year:day, 
  ends_with("delay"), 
  distance, 
  air_time
))
## # A tibble: 336,776 × 7
##     year month   day dep_delay arr_delay distance air_time
##    <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl>
##  1  2013     1     1         2        11     1400      227
##  2  2013     1     1         4        20     1416      227
##  3  2013     1     1         2        33     1089      160
##  4  2013     1     1        -1       -18     1576      183
##  5  2013     1     1        -6       -25      762      116
##  6  2013     1     1        -4        12      719      150
##  7  2013     1     1        -5        19     1065      158
##  8  2013     1     1        -3       -14      229       53
##  9  2013     1     1        -3        -8      944      140
## 10  2013     1     1        -2         8      733      138
## # ℹ 336,766 more rows

Додајемо нове колоне gain и hours:

mutate(df_nyc_small,
  gain = dep_delay - arr_delay,
  hours = air_time / 60
)
## # A tibble: 336,776 × 9
##     year month   day dep_delay arr_delay distance air_time  gain hours
##    <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>
##  1  2013     1     1         2        11     1400      227    -9 3.78 
##  2  2013     1     1         4        20     1416      227   -16 3.78 
##  3  2013     1     1         2        33     1089      160   -31 2.67 
##  4  2013     1     1        -1       -18     1576      183    17 3.05 
##  5  2013     1     1        -6       -25      762      116    19 1.93 
##  6  2013     1     1        -4        12      719      150   -16 2.5  
##  7  2013     1     1        -5        19     1065      158   -24 2.63 
##  8  2013     1     1        -3       -14      229       53    11 0.883
##  9  2013     1     1        -3        -8      944      140     5 2.33 
## 10  2013     1     1        -2         8      733      138   -10 2.3  
## # ℹ 336,766 more rows

Такође, можемо додавати променљиве које су функције оних које смо управо креирали, у истом позиву функције mutate():

mutate(df_nyc_small,
  gain = dep_delay - arr_delay,
  hours = air_time / 60,
  gain_per_hour = gain / hours
)
## # A tibble: 336,776 × 10
##     year month   day dep_delay arr_delay distance air_time  gain hours
##    <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>
##  1  2013     1     1         2        11     1400      227    -9 3.78 
##  2  2013     1     1         4        20     1416      227   -16 3.78 
##  3  2013     1     1         2        33     1089      160   -31 2.67 
##  4  2013     1     1        -1       -18     1576      183    17 3.05 
##  5  2013     1     1        -6       -25      762      116    19 1.93 
##  6  2013     1     1        -4        12      719      150   -16 2.5  
##  7  2013     1     1        -5        19     1065      158   -24 2.63 
##  8  2013     1     1        -3       -14      229       53    11 0.883
##  9  2013     1     1        -3        -8      944      140     5 2.33 
## 10  2013     1     1        -2         8      733      138   -10 2.3  
## # ℹ 336,766 more rows
## # ℹ 1 more variable: gain_per_hour <dbl>

Ако желимо да задржимо само нове променљиве, користимо функцију transmute():

transmute(df_nyc,
  gain = dep_delay - arr_delay,
  hours = air_time / 60,
  gain_per_hour = gain / hours
)
## # A tibble: 336,776 × 3
##     gain hours gain_per_hour
##    <dbl> <dbl>         <dbl>
##  1    -9 3.78          -2.38
##  2   -16 3.78          -4.23
##  3   -31 2.67         -11.6 
##  4    17 3.05           5.57
##  5    19 1.93           9.83
##  6   -16 2.5           -6.4 
##  7   -24 2.63          -9.11
##  8    11 0.883         12.5 
##  9     5 2.33           2.14
## 10   -10 2.3           -4.35
## # ℹ 336,766 more rows

Рачунање сумарних вредности коришћењем функције summarise()

Последња важна функција коју обрађујемо је summarise(). Она налази сумарне вредности за наведене колоне, нпр. средњу вредност, суму, итд.

Да бисмо израчунали просечно кашњење при полетању, примењујемо функцију mean() на колону dep_delay и резултат означимо са avg_delay:

summarise(df_nyc, avg_delay = mean(dep_delay, na.rm = TRUE))
## # A tibble: 1 × 1
##   avg_delay
##       <dbl>
## 1      12.6

Искористили смо аргумент na.rm. Шта се дешава ако га изоставимо?

summarise(df_nyc, avg_delay = mean(dep_delay))
## # A tibble: 1 × 1
##   avg_delay
##       <dbl>
## 1        NA

Добијамо NA вредност, јер ове функције прате уобичајено правило NA вредности: ако постоји било каква NA вредност на улазу, резултат ће бити NA вредност. Срећом, све ове функције имају na.rm аргумент који уклања NA вредности пре израчунавања.

Груписање помоћу функције group_by()

Функција summarise() се најчешће користи у комбинацији са функцијом group_by(). Ово мења јединицу проучавања са читаве базе података на појединачне скупине. Дакле, када користимо summarise() на груписаној бази података, она ће бити примењена “по групама”, тј. израчунаће се сумарне статистике за сваку групу и ти ће се резултати комбиновати на излазу.

На пример, ако применимо претходни код на базу груписану по месецима, добијамо просечно кашњење за сваки месец:

by_month = group_by(df_nyc, month)
summarise(by_month, avg_delay = mean(dep_delay, na.rm = TRUE)) 
## # A tibble: 12 × 2
##    month avg_delay
##    <int>     <dbl>
##  1     1     10.0 
##  2     2     10.8 
##  3     3     13.2 
##  4     4     13.9 
##  5     5     13.0 
##  6     6     20.8 
##  7     7     21.7 
##  8     8     12.6 
##  9     9      6.72
## 10    10      6.24
## 11    11      5.44
## 12    12     16.6

За дегруписање се користи функција ungroup().

summarise(ungroup(by_month), avg_delay = mean(dep_delay, na.rm = TRUE)) 
## # A tibble: 1 × 1
##   avg_delay
##       <dbl>
## 1      12.6

Оператор %>%

Пре него што наставимо даље, упознаћемо се са оператором %>%. Овај оператор нам дозвољава да излаз једне функције користимо као улаз друге функције. Уместо угњеждених функција (које се читају изнутра према ван), идеја овог оператора је читање слева на десно.

На пример:

head(select(df_nyc, month, day))
## # A tibble: 6 × 2
##   month   day
##   <int> <int>
## 1     1     1
## 2     1     1
## 3     1     1
## 4     1     1
## 5     1     1
## 6     1     1

можемо приказати на следећи начин:

df_nyc %>% select(month, day) %>% head
## # A tibble: 6 × 2
##   month   day
##   <int> <int>
## 1     1     1
## 2     1     1
## 3     1     1
## 4     1     1
## 5     1     1
## 6     1     1

Овај оператор је користан када желимо да комбинујемо пуно функција, ради боље читљивости кода и лакшег уочавања грешке.

Дакле, x %>% f(y) се претвара у f(x,y), а x %>% f(y) %>% g(z) се претвара у g(f(x, y), z) и тако даље. Према томе, можемо користити оператор %>% да пишемо наредбе тако да можемо да читамо слева на десно, од врха до дна. Од сада ћемо користити овај оператор јер значајно побољшава читљивост кода.

Корисне функције за summarise()

Илустроваћемо још неке функције које могу бити корисне у комбинацији са summarise() на бази која садржи све летове који нису отказани (постоји податак о тренутку полетања):

not_cancelled = df_nyc %>% filter(!is.na(dep_time))
  • Мере положаја: mean(x), median(x) (mean(x) је аритметичка средина вектора x, а median(x) даје медијану - вредност од које је 50% вредности из x мање, а 50% веће).

Рачунамо просечно кашњење при полетању за сваког превозника:

not_cancelled %>% 
  group_by(carrier) %>% 
  summarise(avg_delay = mean(dep_delay))
## # A tibble: 16 × 2
##    carrier avg_delay
##    <chr>       <dbl>
##  1 9E          16.7 
##  2 AA           8.59
##  3 AS           5.80
##  4 B6          13.0 
##  5 DL           9.26
##  6 EV          20.0 
##  7 F9          20.2 
##  8 FL          18.7 
##  9 HA           4.90
## 10 MQ          10.6 
## 11 OO          12.6 
## 12 UA          12.1 
## 13 US           3.78
## 14 VX          12.9 
## 15 WN          17.7 
## 16 YV          19.0
  • Мере распршености: sd(x), IQR(x) (sd(x) је стандардна девијација, а IQR(x) интерквартилно растојање).
not_cancelled %>% 
  group_by(dest) %>% 
  summarise(distance_sd = sd(distance)) %>% 
  arrange(desc(distance_sd))
## # A tibble: 104 × 2
##    dest  distance_sd
##    <chr>       <dbl>
##  1 EGE         10.5 
##  2 SAN         10.3 
##  3 SFO         10.2 
##  4 HNL         10.0 
##  5 SEA          9.98
##  6 LAS          9.91
##  7 PDX          9.88
##  8 PHX          9.86
##  9 LAX          9.66
## 10 IND          9.47
## # ℹ 94 more rows
  • Мере рангирања: min(x), quantile(x, p), max(x). Квантили су уопштење медијане. На пример, quantile(x, 0.25) ће пронаћи вредност у вектору x која је већа од 25% вредности, а мања од преосталих 75%.

Када полећу први и последњи авион сваког дана?

not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(
    first = min(dep_time),
    last = max(dep_time)
  )
## `summarise()` has grouped output by 'year', 'month'. You can override using the
## `.groups` argument.
## # A tibble: 365 × 5
## # Groups:   year, month [12]
##     year month   day first  last
##    <int> <int> <int> <int> <int>
##  1  2013     1     1   517  2356
##  2  2013     1     2    42  2354
##  3  2013     1     3    32  2349
##  4  2013     1     4    25  2358
##  5  2013     1     5    14  2357
##  6  2013     1     6    16  2355
##  7  2013     1     7    49  2359
##  8  2013     1     8   454  2351
##  9  2013     1     9     2  2252
## 10  2013     1    10     3  2320
## # ℹ 355 more rows
  • Мере позиције: first(x), nth(x, с), last(x).

  • Пребројавања: n() (која нема аргументе) враћа број елемената тренутне групе. Да пребројимо вредности које нису NA, користимо sum(!is.na(x)). Да одредимо број различитих (јединствених) вредности, користимо n_distinct(x).

На које дестинације лети највише превозника?

not_cancelled %>% 
  group_by(dest) %>% 
  summarise(num_of_carriers = n_distinct(carrier)) %>% 
  arrange(desc(num_of_carriers))
## # A tibble: 104 × 2
##    dest  num_of_carriers
##    <chr>           <int>
##  1 ATL                 7
##  2 BOS                 7
##  3 CLT                 7
##  4 ORD                 7
##  5 TPA                 7
##  6 AUS                 6
##  7 DCA                 6
##  8 DTW                 6
##  9 IAD                 6
## 10 MSP                 6
## # ℹ 94 more rows

dplyr обезбеђује пречицу ако желимо само да извршимо пребројавање. На пример, ако желимо да пребројимо летове до сваке дестинације, можемо урадити следеће:

not_cancelled %>% 
  count(dest)
## # A tibble: 104 × 2
##    dest      n
##    <chr> <int>
##  1 ABQ     254
##  2 ACK     265
##  3 ALB     419
##  4 ANC       8
##  5 ATL   16898
##  6 AUS    2418
##  7 AVL     263
##  8 BDL     412
##  9 BGR     360
## 10 BHM     272
## # ℹ 94 more rows

Претходни код заправо ради ово:

not_cancelled %>% 
  group_by(dest) %>%
    summarise(n = n())
  • Број и удео вредности које задовољавају одређени услов: sum(x > c), mean(x > c) (sum(x > c) даје број елемената из x са вредностима већим од c, а mean(x > c) удео елемената из x са вредностима већим од c).

Колико летова је реализовано пре 5 сати ујутру сваког дана?

not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(num_5am = sum(dep_time < 500))
## `summarise()` has grouped output by 'year', 'month'. You can override using the
## `.groups` argument.
## # A tibble: 365 × 4
## # Groups:   year, month [12]
##     year month   day num_5am
##    <int> <int> <int>   <int>
##  1  2013     1     1       0
##  2  2013     1     2       3
##  3  2013     1     3       4
##  4  2013     1     4       3
##  5  2013     1     5       3
##  6  2013     1     6       2
##  7  2013     1     7       2
##  8  2013     1     8       1
##  9  2013     1     9       3
## 10  2013     1    10       3
## # ℹ 355 more rows