library(tidyverse)
library(stringr) # работа со строками
library(nycflights13) # учебный набор данных
# Раскомментируйте и запустите следующие команды,
# если у вас не ставится tidyverse
#library(dplyr)
#library(tidyr)
Процесс анализа данных
Трансформация данных - это выполнение различных преобразований данных с целью их подготовки к анализу. Среди наиболее часто используемых операций - отбор строк или столбцов таблицы данных, вычисление новых столбцов, подсчет итогов, группировка и ранжирование. Также часто востребованы слияние данных из разных таблиц и изменение формы данных (реструктурирование таблиц).
В этом блокноте показаны наиболее полезные приемы трансформации данных в R. Мы будем использовать пакеты dplyr и tidyr.
Также будет рассмотрено создание “конвейеров” по обработке данных с помощью оператора %>%.
Более подробно познакомиться с трансформацией данных вы можете в следующих главах книги R for Data Science:
Также полезно знать, как работать с факторами, строками и датами.
В RStudio всегда под рукой “шпаргалки” по трансформации данных - см. Help>Cheatsheets.
Пакет dplyr реализует концепцию грамматики трансформации данных, согласно которой любое преобразование данных можно описать как последовательность шагов, обозначающих определенное действие с данными. В терминологии dplyr эти действия называются глаголами (verbs). Каждое действие реализовано как функция пакета, которая принимает на вход таблицу данных и возвращает преобразованную таблицу. Например, глагол select() позволяет отобрать из таблицы нужные столбцы:
select(my_table, important_column1, important_column2)
Все функции используют один и тот же порядок аргументов: первый аргумент - входная таблица данных, последующие агрументы - параметры, описывающие детали преобразования данных. В предыдущем примере это был список необходимых столбцов.
data(mpg) #загрузка набора данных о топливной эффективности автомобилей
head(mpg)
## # A tibble: 6 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manua~ f 21 29 p comp~
## 3 audi a4 2 2008 4 manua~ f 20 31 p comp~
## 4 audi a4 2 2008 4 auto(~ f 21 30 p comp~
## 5 audi a4 2.8 1999 6 auto(~ f 16 26 p comp~
## 6 audi a4 2.8 1999 6 manua~ f 18 26 p comp~
head(
select(mpg, manufacturer, model, displ, trans, cty) #отбор 5 столбцов
)
## # A tibble: 6 x 5
## manufacturer model displ trans cty
## <chr> <chr> <dbl> <chr> <int>
## 1 audi a4 1.8 auto(l5) 18
## 2 audi a4 1.8 manual(m5) 21
## 3 audi a4 2 manual(m6) 20
## 4 audi a4 2 auto(av) 21
## 5 audi a4 2.8 auto(l5) 16
## 6 audi a4 2.8 manual(m5) 18
Благодаря тому, что на входе и выходе каждой функции используются таблицы, “глаголы”, преобразующие данные, можно выстраивать в своеобразные “предложения” - цепочки, описывающие, как получить желаемый результат.
Предложение, составленное из глаголов dplyr
Мы рассмотрим самые важные глаголы:
filter() - отобрать строки,mutate() - вычислить новые столбцы,select() - отобрать столбцы,arrange() - упорядочить строки,group_by() и summarize() - посчитать итоги по группамВ блокноте tidy_data.Rmd вы можете узнать о глаголах для переструктурирования таблиц:
gather() - “свернуть” столбцы в строки, перейти к “длинному” формату,spread() - “развернуть” строки в столбцы, перейти к “широкому” формату.Большинство функций реализованы в пакете dplyr. Функции для преобразования структуры данных gather() и spread() реализованы в пакете tidyr. Оба пакета автоматически подключаются при загрузке tidyverse.
Для слияния нескольких таблиц в dplyr существуют глаголы для соединения, объединения и дополнения столбцов: - inner_join() - соединить таблицы внутренним соединением - left_join() - соединить таблицы левым соединением и др.
С ними можно познакомиться в главе Relational Data книги R for Data Science и документации на dplyr.
filter()Функция filter() позволяет отобрать нужные строки таблицы по условию.
Отбор строк с помощью filter()
Совет в RStudio открыть картинку в большем размере можно щелкнув по ней или по ссылке с зажатой клавишей Shift. Если выдается сообщение об ошибке (не найден файл) - установите рабочий каталог на папку, в которой находится этот блокнот (Session>Set Working Directory>To Source File Location).
Поддерживаются следующие условия:
< <= > >===, неравенство: !=near(pi, 3.14, tol = 0.01) (с указанием точности)is.na(), !is.na()%in%Несколько условий можно комбинировать с помощью логических союзов:
Логические союзы
filter()Отобрать все машины с задним приводом и 6-цилиндровым двигателем.
filter(mpg, drv == 'r' & cyl == 6)
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 ford musta~ 3.8 1999 6 manu~ r 18 26 r subc~
## 2 ford musta~ 3.8 1999 6 auto~ r 18 25 r subc~
## 3 ford musta~ 4 2008 6 manu~ r 17 26 r subc~
## 4 ford musta~ 4 2008 6 auto~ r 16 24 r subc~
# или так:
filter(mpg, drv == 'r', cyl == 6)
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 ford musta~ 3.8 1999 6 manu~ r 18 26 r subc~
## 2 ford musta~ 3.8 1999 6 auto~ r 18 25 r subc~
## 3 ford musta~ 4 2008 6 manu~ r 17 26 r subc~
## 4 ford musta~ 4 2008 6 auto~ r 16 24 r subc~
Действительные числа хранятся с ограниченной точностью. Это может вызывать проблемы при сравнении таких чисел на строгое равенство:
# Нельзя использовать для действительных чисел:
sqrt(2)^2 == 2
## [1] FALSE
sprintf("%.30f", sqrt(2)^2)
## [1] "2.000000000000000444089209850063"
Безопаснее пользоваться функцией near():
# Правильно сравнивать действительные числа так:
near(sqrt(2)^2, 2)
## [1] TRUE
Отобрать автомобили марок Honda и Toyota с автоматической коробкой передач и объемом двигателя 1.8 литра.
filter(mpg,
manufacturer %in% c('honda', 'toyota'),
str_detect(trans, 'auto'),
near(displ, 1.8))
## # A tibble: 5 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 honda civic 1.8 2008 4 auto~ f 25 36 r subc~
## 2 honda civic 1.8 2008 4 auto~ f 24 36 c subc~
## 3 toyota corol~ 1.8 1999 4 auto~ f 24 30 r comp~
## 4 toyota corol~ 1.8 1999 4 auto~ f 24 33 r comp~
## 5 toyota corol~ 1.8 2008 4 auto~ f 26 35 r comp~
Отобрать автомобили, в которых средневзвешенный пробег на 1 галлоне топлива (город - 50%, шоссе - 50%) свыше 30 миль.
filter(mpg,
0.5 * cty + 0.5 * hwy > 30)
## # A tibble: 8 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 honda civic 1.6 1999 4 manu~ f 28 33 r subc~
## 2 honda civic 1.8 2008 4 auto~ f 25 36 r subc~
## 3 toyota corol~ 1.8 1999 4 manu~ f 26 35 r comp~
## 4 toyota corol~ 1.8 2008 4 manu~ f 28 37 r comp~
## 5 toyota corol~ 1.8 2008 4 auto~ f 26 35 r comp~
## 6 volkswagen jetta 1.9 1999 4 manu~ f 33 44 d comp~
## 7 volkswagen new b~ 1.9 1999 4 manu~ f 35 44 d subc~
## 8 volkswagen new b~ 1.9 1999 4 auto~ f 29 41 d subc~
Замечание: в качестве условия отбора можно использовать любое выражение, которое возвращает TRUE или FALSE для каждой строки обрабатываемой таблицы.
filter()Для выполнения упражнений понадобится набор данных flights, который устанавливается вместе с пакетом nycflights13.
data(flights)
head(flights)
## # A tibble: 6 x 19
## year month day dep_time 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
## # ... with 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>
Посмотреть описание столбцов можно командой: ?flights.
Найдите все рейсы компаний ‘Delta Airlines’, ‘American Airlines’ и ‘United Airlines’, которые вылетели в Хьюстон (IAH или HOU) летом 2013 года. При этом рейс должен был вылететь без опоздания, но совершить посадку с задержкой более 1 часа.
Коды авиакомпаний можно посмотреть в таблице: nycflights13::airlines.
#filter(flights,
# ...
# )
Должно получиться 7 строк.
Подсказки:
& их можно перечислить через запятую в списке аргументов filter().dplyr имеется функция between(), которая может использоваться для отбора по условию вхождения в интервал значений. Обратите внимание, что границы интервала входят в него.Найдите рейсы, вылетевшие в ночное время (с 00:00 до 5:59) с задержкой не менее 1 часа и наверставшие в пути более 50 минут.
# Напишите свой код здесь
Должно получиться 7 строк.
Сколько рейсов в Питтсбург отменили в сентябре 2013 года?
# Напишите свой код здесь
Должно получиться 5 строк.
select()Глагол select() позволяет отобрать нужные столбцы таблицы.
Отбор столбцов с помощью select()
Указать, какие столбцы нужны, можно следующими способами:
перечислить их в списке аргументов select()
указать последовательность для включения начало:конец или исключения: -(начало:конец)
использовать вспомогательные функции для выбора столбцов:
starts_with('abc') - имя начинается с abcends_with('xyz') - имя заканчивается на abccontains('ijk') - имя содержит ijkmatches('\d') - имя соответствует регулярному выражению (см. книгу R4DS), в даном случае - содержит любую цифруnum_range('x', 1:3) - имя входит в последовательность: x1, x2, x3one_of(c('a', 'b', 'c')) - имя входит в список: a, b, ceverything() - все остальные столбцы.select()names(mpg)
## [1] "manufacturer" "model" "displ" "year"
## [5] "cyl" "trans" "drv" "cty"
## [9] "hwy" "fl" "class"
head(mpg)
## # A tibble: 6 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manua~ f 21 29 p comp~
## 3 audi a4 2 2008 4 manua~ f 20 31 p comp~
## 4 audi a4 2 2008 4 auto(~ f 21 30 p comp~
## 5 audi a4 2.8 1999 6 auto(~ f 16 26 p comp~
## 6 audi a4 2.8 1999 6 manua~ f 18 26 p comp~
head(
select(mpg, manufacturer:displ, trans, cty)
)
## # A tibble: 6 x 5
## manufacturer model displ trans cty
## <chr> <chr> <dbl> <chr> <int>
## 1 audi a4 1.8 auto(l5) 18
## 2 audi a4 1.8 manual(m5) 21
## 3 audi a4 2 manual(m6) 20
## 4 audi a4 2 auto(av) 21
## 5 audi a4 2.8 auto(l5) 16
## 6 audi a4 2.8 manual(m5) 18
head(
select(mpg, -(displ:cty), -fl, -class)
)
## # A tibble: 6 x 3
## manufacturer model hwy
## <chr> <chr> <int>
## 1 audi a4 29
## 2 audi a4 29
## 3 audi a4 31
## 4 audi a4 30
## 5 audi a4 26
## 6 audi a4 26
Отобрать столбцы, которые начинаются на ‘m’ или содержат ‘y’.
head(
select(mpg, starts_with('m'), contains('y'))
)
## # A tibble: 6 x 6
## manufacturer model year cyl cty hwy
## <chr> <chr> <int> <int> <int> <int>
## 1 audi a4 1999 4 18 29
## 2 audi a4 1999 4 21 29
## 3 audi a4 2008 4 20 31
## 4 audi a4 2008 4 21 30
## 5 audi a4 1999 6 16 26
## 6 audi a4 1999 6 18 26
head(
select(mpg, cty, hwy, everything())
)
## # A tibble: 6 x 11
## cty hwy manufacturer model displ year cyl trans drv fl class
## <int> <int> <chr> <chr> <dbl> <int> <int> <chr> <chr> <chr> <chr>
## 1 18 29 audi a4 1.8 1999 4 auto(~ f p comp~
## 2 21 29 audi a4 1.8 1999 4 manua~ f p comp~
## 3 20 31 audi a4 2 2008 4 manua~ f p comp~
## 4 21 30 audi a4 2 2008 4 auto(~ f p comp~
## 5 16 26 audi a4 2.8 1999 6 auto(~ f p comp~
## 6 18 26 audi a4 2.8 1999 6 manua~ f p comp~
select()Для выполнения задания вам потребуется набор данных flights.
head(flights)
## # A tibble: 6 x 19
## year month day dep_time 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
## # ... with 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>
Придумайте как можно больше способов, которыми можно извлечь из таблицы все переменные, относящиеся ко времени или задержке вылета.
# Напишите свой код здесь
arrange()Глагол arrange() позволяет упорядочить таблицу по одному или нескольким столбцам. По умолчанию сортировка производится по возрастанию. Используйте функцию desc() для сортировки по убыванию.
arrange()Выведите рейтинг из 10 наиболее экономичных автомобилей (при поездках по городу)?
head(
arrange(mpg, desc(cty)),
n = 10)
## # A tibble: 10 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 volkswagen new ~ 1.9 1999 4 manu~ f 35 44 d subc~
## 2 volkswagen jetta 1.9 1999 4 manu~ f 33 44 d comp~
## 3 volkswagen new ~ 1.9 1999 4 auto~ f 29 41 d subc~
## 4 honda civic 1.6 1999 4 manu~ f 28 33 r subc~
## 5 toyota coro~ 1.8 2008 4 manu~ f 28 37 r comp~
## 6 honda civic 1.8 2008 4 manu~ f 26 34 r subc~
## 7 toyota coro~ 1.8 1999 4 manu~ f 26 35 r comp~
## 8 toyota coro~ 1.8 2008 4 auto~ f 26 35 r comp~
## 9 honda civic 1.6 1999 4 manu~ f 25 32 r subc~
## 10 honda civic 1.8 2008 4 auto~ f 25 36 r subc~
Выведите рейтинг автомобилей по экономичности в городе для каждого производителя.
head(
arrange(mpg, manufacturer, desc(cty)),
n = 30)
## # A tibble: 30 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 manu~ f 21 29 p comp~
## 2 audi a4 2 2008 4 auto~ f 21 30 p comp~
## 3 audi a4 2 2008 4 manu~ f 20 31 p comp~
## 4 audi a4 q~ 2 2008 4 manu~ 4 20 28 p comp~
## 5 audi a4 q~ 2 2008 4 auto~ 4 19 27 p comp~
## 6 audi a4 1.8 1999 4 auto~ f 18 29 p comp~
## 7 audi a4 2.8 1999 6 manu~ f 18 26 p comp~
## 8 audi a4 3.1 2008 6 auto~ f 18 27 p comp~
## 9 audi a4 q~ 1.8 1999 4 manu~ 4 18 26 p comp~
## 10 audi a4 q~ 2.8 1999 6 manu~ 4 17 25 p comp~
## # ... with 20 more rows
arrange()Для выполнения задания вам потребуется набор данных flights.
head(flights)
## # A tibble: 6 x 19
## year month day dep_time 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
## # ... with 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>
Вылет каких рейсов был больше всего задержан?
Какие рейсы самые быстрые (по скорости движения в воздухе)?
mutate().Для вычисления новых столбцов в таблице на основе уже существующих удобно применять функцию mutate(). Можно вычислить сразу несколько новых столбцов. Для каждого нового столбца необходимо задать расчетную формулу с использованием имен существующих столбцов, арифметических операций и различных функций R.
Функция mutate() всегда добавляет столбцы в конце таблицы. Если исходные столбцы не нужны, то можно использовать функцию transmute(), которая оставляет только вычисленные столбцы.
mutate()Пусть требуется рассчитать средневзвешенную топливную эффективность для условий, когда доля поездок по городу составляет 50% и 80%.
head(
mutate(mpg,
mpg_city50 = 0.5 * cty + 0.5 * hwy,
mpg_city80 = 0.8 * cty + 0.2 * hwy)
)
## # A tibble: 6 x 13
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manu~ f 21 29 p comp~
## 3 audi a4 2 2008 4 manu~ f 20 31 p comp~
## 4 audi a4 2 2008 4 auto~ f 21 30 p comp~
## 5 audi a4 2.8 1999 6 auto~ f 16 26 p comp~
## 6 audi a4 2.8 1999 6 manu~ f 18 26 p comp~
## # ... with 2 more variables: mpg_city50 <dbl>, mpg_city80 <dbl>
ifelse()Формула для расчета нового столбца применяется сразу ко всей таблице. Если необходимо проводить расчет по разным формулам для отдельных записей, то можно использовать функцию ifelse().
Предположим, что доли поездок по городу для разных автомобилей в таблице отличаются. Для наглядности, будем считать, что автомобили классов minivan и 2seater используются только в городе, а остальные - по 50% времени в городе и для поездок по автомагистралям. Требуется рассчитать средневзвешенную топливную эффективность.
head(
filter(
mutate(mpg,
weighted_mpg =
ifelse(class %in% c('pickup', '2seater'),
cty, 0.5 * cty + 0.5 * hwy)),
class %in% c('2seater', 'suv')))
## # A tibble: 6 x 12
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 chevrolet c150~ 5.3 2008 8 auto~ r 14 20 r suv
## 2 chevrolet c150~ 5.3 2008 8 auto~ r 11 15 e suv
## 3 chevrolet c150~ 5.3 2008 8 auto~ r 14 20 r suv
## 4 chevrolet c150~ 5.7 1999 8 auto~ r 13 17 r suv
## 5 chevrolet c150~ 6 2008 8 auto~ r 12 17 r suv
## 6 chevrolet corv~ 5.7 1999 8 manu~ r 16 26 p 2sea~
## # ... with 1 more variable: weighted_mpg <dbl>
mutate()Для выполнения задания вам потребуется набор данных flights.
head(flights)
## # A tibble: 6 x 19
## year month day dep_time 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
## # ... with 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>
В наборе данных время вылета находится в неудобном формате: часы и минуты собраны в одно целое число. Поэтому, например, после значения 1359 будет идти значение 1400. Ваша задача - вычислить три новых поля: dep_hour, dep_minute и dep_minutes_since_midnight. Поля должны содержать, соответственно, час вылета, минуту вылета и количество минут с полуночи до вылета.
# Напишите свой код здесь
Подсказки:
Воспользуйтесь операциями целочисленного деления %/% и взятия остатка от деления %%. Например, 1359 %/% 100 = 13, а 1359 %% 100 = 59.
Добавив формулу для расчета столбца, вы можете использовать имя этого столбца в этом же вызове функции mutate() для расчета новых столбцов. Т.е. можно сделать так: mutate(mpg, cty2 = cty, cty3 = cty2).
Некоторые рейсы были отменены. Для таких рейсов в столбце dep_time содержится пропущенное значение. Вычислите новый столбец: status, который, в зависимости от времени задержки вылета, должен содержать одно из следующих значений: вылетел вовремя, задержан, отменен. Для упрощения расчета, примите, что те рейсы, которые вылетели раньше назначенного времени, также относятся к категории: вылетел вовремя.
# Напишите свой код здесь
%>%В большинстве случаев преобразование данных к нужной структуре требует несколько последовательных операций с таблицей данных. В примере про условные вычисления потребовалось выполнить следующие шаги:
weighted_mpg с помощью mutate()filter()head()Однако записывать эти действия приходится в обратном порядке, вкладывая функцию предыдущего шага внутрь функции, использующейся на следующем шаге преобразования:
head(
filter(
mutate(...)
)
)
Такой код сложно понять.
Мы могли бы улучшить наглядность кода, используя дополнительные переменные для сохранения промежуточных результатов:
step1 <- mutate(mpg, ...)
step2 <- filter(step1, ...)
head(step2)
Здесь действия по преобразованию данных расположены в естественном порядке. Однако при реальной работе этот подход также неудобно использовать, поскольку для различных действий пришлось бы создавать временные переменные, которые расходуют память и могут привести к путанице и ошибкам в расчетах.
Чтобы обеспечить “последовательную” логику выполнения шагов преобразования данных, для R был создан пакет magrittr, который позволяет использовать новый оператор - %>% (pipe) для записи цепочек преобразования данных.
Оператор подставляет любой объект в своей левой части в качестве первого аргумента функции, указанной в правой части.
Как работает конвейер %>%
Предыдущая запись эквивалентна: function(object, arg2, ...)
Поскольку функции в R возвращают новые объекты, цепочку операций можно продолжать сколько угодно. Результат предыдущей операции используется в качестве первого аргумента второй операции.
Конвейер из двух операций
Эквивалентная запись: function2(function1(object))
%>%Применим конвейер, чтобы более наглядно записать процесс обработки данных в предыдущем примере:
Было:
head(
filter(
mutate(mpg,
weighted_mpg =
ifelse(class %in% c('pickup', '2seater'),
cty, 0.5 * cty + 0.5 * hwy)),
class %in% c('2seater', 'suv')))
Стало:
mpg %>%
mutate(weighted_mpg =
ifelse(class %in% c('pickup', '2seater'),
cty, 0.5 * cty + 0.5 * hwy)) %>%
filter(class %in% c('2seater', 'suv')) %>%
select(model, cty, hwy, class, weighted_mpg) %>%
head()
## # A tibble: 6 x 5
## model cty hwy class weighted_mpg
## <chr> <int> <int> <chr> <dbl>
## 1 c1500 suburban 2wd 14 20 suv 17
## 2 c1500 suburban 2wd 11 15 suv 13
## 3 c1500 suburban 2wd 14 20 suv 17
## 4 c1500 suburban 2wd 13 17 suv 15
## 5 c1500 suburban 2wd 12 17 suv 14.5
## 6 corvette 16 26 2seater 16
Для удобства, мы добавили дополнительный шаг, оставив в таблице только нужные столбцы.
Замечание: обратите внимание, что при включении функции в конвейер аргументы в списке надо указывать начиная со второго. Первый аргумент автоматически заполняется оператором %>%.
Результаты обработки данных можно сохранить в переменную. В этом случае туда запишется результат последней операции конвейера:
final_result <- initial_data %>% step1() %>% step2() %>% last_step()
В dplyr И многих других функциях R принято, что первый аргумент функции - это обрабатываемые ей данные, поэтому %>% удобно использовать не только для преобразования табличных данных, но и в других ситуациях, требующих нескольких последовательных шагов.
Некоторые функции все же ожидают, что данные будут переданы им не в первом, а в одном из следующих аргументов. Например, функция lm() для построения линейных моделей ждет данные во втором аргументе. См. справку: ?lm.
В этой ситуации можно указать место куда оператор %>% должен подставлять данные с предыдущего шага, с помощью точки: .
В качестве примера, построим модель зависимости топливной эффективности только для автомобилей класса compact, отобрав их с помощью фильтрации.
mpg %>%
filter(class == 'compact') %>%
lm(cty ~ hwy, data = .) %>%
summary()
##
## Call:
## lm(formula = cty ~ hwy, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.7171 -0.3593 0.2463 0.4802 2.6407
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -3.62688 1.32391 -2.74 0.00879 **
## hwy 0.83945 0.04638 18.10 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.19 on 45 degrees of freedom
## Multiple R-squared: 0.8792, Adjusted R-squared: 0.8765
## F-statistic: 327.6 on 1 and 45 DF, p-value: < 2.2e-16
Функция summarise() позволяет агрегировать данные, вычисляя итоги для множества записей.
Некоторые востребованные функции для подсчета итогов приведены ниже:
mean() - среднееsum() - суммаn() - количество записейsd() - стандартное отклонениеfirst()/last() - первый/последний по порядку элементmin()/max() - наименьший и наибольший элементquantile(x, p) - квантиль уровня psummarise()mpg %>% summarise(avg_cty = mean(cty),
median_cty = median(cty),
iqr_cty = IQR(cty),
n_obs = n(),
percent_mising = 100 * mean(is.na(cty)))
## # A tibble: 1 x 5
## avg_cty median_cty iqr_cty n_obs percent_mising
## <dbl> <dbl> <dbl> <int> <dbl>
## 1 16.9 17 5 234 0
group_by()Подсчет итогов для всей таблицы может использоваться на этапе контроля качества загруженных данных, в дополнение к стандартным возможностям, предоставляемым функцией summary().
В большинстве же случаев подсчет итогов проводится по группам. Для этого необходимо задать условие группировки набора данных с помощью функции group_by().
Сама по себе функция group_by() никак не изменяет данные, однако она добавляет информацию о группировке в свойства таблицы данных.
mpg %>% group_by(manufacturer) %>% head()
## # A tibble: 6 x 11
## # Groups: manufacturer [1]
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manua~ f 21 29 p comp~
## 3 audi a4 2 2008 4 manua~ f 20 31 p comp~
## 4 audi a4 2 2008 4 auto(~ f 21 30 p comp~
## 5 audi a4 2.8 1999 6 auto(~ f 16 26 p comp~
## 6 audi a4 2.8 1999 6 manua~ f 18 26 p comp~
Информация о группировке используется в дальнейшем при выполнении функции summarise(). Если задана группировка, то итоги считаются по группам.
Составим рейтинг автопроизводителей по средней топливной эффективности их автомобилей.
mpg %>%
group_by(manufacturer) %>%
summarise(average_cty = mean(cty)) %>%
arrange(desc(average_cty)) %>%
top_n(5, wt = average_cty)
## # A tibble: 5 x 2
## manufacturer average_cty
## <chr> <dbl>
## 1 honda 24.4
## 2 volkswagen 20.9
## 3 subaru 19.3
## 4 hyundai 18.6
## 5 toyota 18.5
Замечание: обратите внимание, что после выполнения агрегирующей функции статус группировки снимается.
Группировать можно по нескольким столбцам, в этом случае будет выполнена многоуровневая группировка. А при последующем подсчете итогов функцию summarise() можно применить несколько раз, причем каждый последующий вызов этой функции будет обрабатывать все более высокий уровень группировки.
В качестве примера, определим лучшего производителя в каждом классе автомобилей на основе средней топливной эффективности.
# Средний расход по типу машины и производителю
mpg_class_manuf <- mpg %>%
group_by(class, manufacturer) %>%
summarise(average_cty = mean(cty)) %>%
arrange(desc(average_cty))
head(mpg_class_manuf)
## # A tibble: 6 x 3
## # Groups: class [3]
## class manufacturer average_cty
## <chr> <chr> <dbl>
## 1 subcompact honda 24.4
## 2 subcompact volkswagen 24
## 3 compact toyota 22.2
## 4 compact volkswagen 20.8
## 5 compact nissan 20
## 6 midsize nissan 20
Применив на нижнем уровне группировку функцию для подсчета средней эффективности автомобиля, мы получили сгруппированную таблицу данных, в которой остался верхний уровень группировки - класс автомобиля.
Теперь мы можем “снять” еще один уровень группировки - по классу автомобиля - чтобы выбрать лучшего производителя в каждом классе.
mpg_class_manuf %>%
top_n(1, wt = average_cty)
## # A tibble: 7 x 3
## # Groups: class [7]
## class manufacturer average_cty
## <chr> <chr> <dbl>
## 1 subcompact honda 24.4
## 2 compact toyota 22.2
## 3 midsize nissan 20
## 4 suv subaru 18.8
## 5 minivan dodge 15.8
## 6 pickup toyota 15.6
## 7 2seater chevrolet 15.4
При необходимости снять группировку с таблицы, можно воспользоваться функцией ungroup().
Для часто используемых операций в dplyr есть вспомогательные функции, которые можно использовать без summarise().
# Подсчет частот по группам
mpg %>% count(manufacturer)
## # A tibble: 15 x 2
## manufacturer n
## <chr> <int>
## 1 audi 18
## 2 chevrolet 19
## 3 dodge 37
## 4 ford 25
## 5 honda 9
## 6 hyundai 14
## 7 jeep 8
## 8 land rover 4
## 9 lincoln 3
## 10 mercury 4
## 11 nissan 13
## 12 pontiac 5
## 13 subaru 14
## 14 toyota 34
## 15 volkswagen 27
# Top-n анализ - самые объемные двигатели
mpg %>% top_n(n = 3, wt = displ)
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 chevrolet corve~ 6.2 2008 8 manu~ r 16 26 p 2sea~
## 2 chevrolet corve~ 6.2 2008 8 auto~ r 15 25 p 2sea~
## 3 chevrolet corve~ 7 2008 8 manu~ r 15 24 p 2sea~
## 4 chevrolet k1500~ 6.5 1999 8 auto~ 4 14 17 d suv
На основе набора данных flights рассчитайте долю задержанных рейсов по всей таблице.
Подсказка: R рассматривает логические значения TRUE и FALSE как 1 и 0. Поэтому выполнив команду: mean(x > 0) мы можем найти долю положительных значений в векторе x.
# Напишите свой код здесь
Составьте рейтинг авиакомпаний по вероятности отмены рейса. Самые надежные авиакомпании должны быть первыми в списке.
# Напишите свой код здесь
Определите, какой месяц оказался самым тяжелым для каждой авиакомпании (по доле рейсов, задержанных более чем на 15 минут).
# Напишите свой код здесь