Страница 16 из 19
неотмененные %>% group_by(year, month, day) %>%
summarise(утренние_рейсы = sum(dep_time < 600))
Какова доля неотмененных рейсов, задержавшихся более часа:
неотмененные %>% group_by(year, month, day) %>%
summarise(часовая_задержка = mean(arr_delay >= 61))
При группировании по нескольким переменным, каждая новая сводка выносится на новый уровень группировки. Это облегчает восприятие и постепенно упрощает данные:
группы_по_дням <– group_by(flights, year, month, day)
(сводка_по_дням <– summarise(группы_по_дням, полётов = n()))
(сводка_по_месяцам <– summarise(сводка_по_дням, полётов = sum(полётов)))
(сводка_за_год <– summarise(сводка_по_месяцам, полётов = sum(полётов)))
Будьте осторожны при постепенном сворачивании выборки, это приемлемо для итоговых сумм и счетчиков, но нужно не забывать про такие характеристики, как медиана и отклонение, анализ результатов свёртки принципиально невозможен в ранговой статистике. Другими словами, сумма внутригрупповых сумм является общей суммой, но медиана внутригрупповых медиан не будет равна общей медиане, о последнем свойстве порой сознательно забывают при выведении нужных результатов из различных голосований. Если потребуется отменить группировку, и вернуться к операции с негруппированными данными, то используется функция ungroup():
группы_по_дням %>%
ungroup() %>% # разгруппируем данные обратно
summarise(полётов = n()) # подсчитаем все полёты
Упражнения
1. Примените мозговой штурм чтобы изобрести как минимум 7 различных способов анализа типовых причин серийной задержки рейсов, учитывая следующие сценарии:
а) в 50% случаев вылет осуществляется на 15 минут раньше запланированного, и в 50% рейс задерживается на 15 минут.
б) рейс всегда опаздывает на 10 минут.
в) 50% рейсов вылетает на 30 минут раньше, и 50% на 30 минут опаздывает.
г) в 99% случаев рейс выполняется точно по графику, а в оставшемся 1% происходит опоздание на 2 часа.
Что более важно для пассажира, задержка прибытия или задержка вылета, а для работы аэропортов?
2. Придумайте альтернативный способ решения той же задачи, что и в примерах неотмененные %>% count (dest), неотмененные %>% count(tailnum, wt = distance), но без использования функции count().
3. Следующее определение отмененных рейсов не оптимально:
отмененные <– flights %>%
filter( is.na(dep_delay) | is.na(arr_delay) )
Почему? Какая колонка важнее в этом случае: задержка времени вылета (dep_delay) или задержка времени прилёта (arr_delay)?
4. Посмотрите на ежедневное количество отмененных рейсов. Есть ли здесь закономерность? Связана ли доля отмененных рейсов со средней задержкой?
5. Какой перевозчик (carrier) имеет худшую статистику по задержкам рейсов? Можно ли обнаружить зависимость плохих статистических показателей аэропортов от качества работы перевозчиков? Если да, то как, если нет, то почему?
6. За что отвечает аргумент выбора способа сортировки sort в функции count()? Когда уместно его использование?
Группирование данных бывает полезным в сочетании с функцией подведения итогов summarise(), но есть удобные шаблоны и для операций преобразования mutate() с фильтрацией filter(). Вспомним про укороченный_вариант_таблицы <– select(flights, year:day, ends_with("delay"), distance, air_time), хранящий лишь сведения об опозданиях, и выделим по 5 злостных нарушителей регламента полётов на каждый день:
укороченный_вариант_таблицы %>% group_by(year, month, day) %>%
filter(rank(desc(arr_delay)) <= 5)
Сгруппируем рейсы по направлениям и оставим лишь такие группы, объем которых превышает некоторое пороговое значение:
( популярные_направления <– flights %>% group_by(dest) %>%
filter(n() > 17282) )
Преобразуем их для дальнейшего вычисления метрических характеристик внутри каждой из полученных групп:
популярные_направления %>% filter(arr_delay > 0) %>%
mutate(относительная_задержка = arr_delay / sum(arr_delay)) %>%
select(year:day, dest, arr_delay, относительная_задержка)
Как видим, группирующая фильтрация приводит к изменениям, за которыми следует обычная фильтрация. Желательно избегать подобного, за исключением поверхностного анализа данных, в противном случае бывает трудно проверить корректность выполненных манипуляций. Функции, которые наиболее естественно работают со сгруппированными данными, например mutate() и filter(), называются оконными функциями, в отличие от резюмирующих функций типа summary(). Узнать больше об оконных функциях можно вызвав соответствующий раздел справки, введя консольную команду vignette("window-functions").
Упражнения
1. Вернитесь к примерам использования функций mutate() и filter() со списками. Как меняется результат каждой операции при создании промежуточных групп данных?
2. Какой самолет (бортовой номер) имеет рекордно худшее время вылета?
3. В какое время суток нужно лететь, чтобы максимальное избежать задержек?
4. Для каждого пункта назначения вычислите суммарное время задержек. Для каждого рейса вычислите долю его задержек в общей сумме.
5. Задержки обычно коррелируют по времени: после того как вызвавшая первоначальную задержку проблема была решена, более поздние рейсы задерживаются, чтобы разрешить ранним покинуть аэропорт. При помощи функции lag() исследуйте, как задержка каждого рейса связана с задержкой непосредственно предшествующего.
6. Просмотрите каждый пункт назначения. Можно ли найти рейсы, долетевшие подозрительно быстро? То есть те полеты, которые потенциально представляют собой ошибку ввода данных. Вычислите долю воздушного времени полета относительно самого скоростного рейса до выбранного пункта назначения. Какие рейсы были дольше всего задержаны в воздухе?
7. Найдите все пункты назначения, в которые одновременно следовало как минимум два перевозчика. Используйте эту информацию для ранжирования перевозчиков.
8. У каждого самолета найдите количество рейсов до первой задержки более 1 часа.
§3. Организация рабочего процесса
Теперь у читателя есть некоторый опыт выполнения кода R, без погружения в детали, но достаточный, чтобы разобраться в основах, иначе эта книга уже была бы закрыта. Разочарование естественно, когда начинаете программировать на R, потому что этот язык требователен к пунктуации, и даже один неуместно поставленный символ может заставить крепко попотеть в поисках допущенной ошибки. Но пока разочарование не зашло слишком далеко, можно утешиться тем, что описанное неудобство типично и главное – временно, такое происходит со всеми, а чтобы преодолеть его, нужно продолжать программировать на R. Прежде чем мы пойдем дальше, убедимся в наличии прочных навыков выполнения кода R, и узнаем о некоторых наиболее полезных функциях редактора RStudio. Рассмотрим некоторые базовые соглашения языка, которые до сих были пропущены в интересах скорейшего погружения в тематику. Во-первых, можно использовать R в качестве калькулятора:
2*2
#> [1] 4
sin(pi/2)
#> [1] 1
Но только в поле действительных чисел, что естественно для языка программирования статистической обработки данных и построения графиков:
(-1)^(1/2)
#> [1] NaN
(-1+0i)^(1/2)
#> [1] 0+1i
Можно создавать новые объекты с помощью оператора <-:
x <– 2*2
Все команды R, которыми создаются объекты путём присваивания, имеют одинаковую форму:
имя_объекта <– получаемое_значение
При чтении этого кода в вашей голове может прозвучать: объект «имя_объекта» получает значение «получаемое_значение». В дальнейшем понадобится решать много интересных задач, набирая большие тексты при этом. Не ленитесь, используя знак =, он тоже будет работать, но позднее приведет к путанице. Вместо этого используйте клавиатурное сокращение RStudio: Alt + – (знак минус) для быстрого набора <-. Обратите внимание, что RStudio автоматически окружает <– пробелами. Приятно читать хорошо оформленный код, поэтому недайсвоимглазамсломаться, используйте пробелы.