Бигдата и такси: как найти самое нагруженное время

Бигдата и такси: как найти самое нагруженное время

Анализируем миллион записей и смотрим на результат

Сегодня будет простой проект с бигдатой на Python: мы проанализируем миллион записей и посмотрим, в какой день недели и время совершается больше всего поездок.

Если коротко, то бигдата — это какой-то большой набор данных: сотни тысяч и миллионы записей. Их можно специальным образом обработать и получить понятный анализ по разным направлениям: чего получилось больше, чего меньше, что с чем связано и как одно зависит от другого. Например, после анализа бигдаты с твитами Байдена и Трампа стало понятно, что за одного твиты пишет команда, а второй постит сам, от чистого сердца.

Что делаем

Мы нашли большой датасет (1 028 136 записей) с записями вызовов такси Uber в США, где хранятся:

  • дата и время вызова;
  • координаты, откуда клиент вызвал такси;
  • порядковый номер местной станции Uber.

Попробуем проанализировать эти данные и понять, в какое время там вызывают такси чаще всего и правда ли, что в выходные такси пользуются чаще, чем в будни. Для этого мы напишем программу на Python и добавим визуализацию — построим понятные графики с распределением вызовов.

Скачать датасет

Считываем и проверяем датасет

Создадим новый Python-файл в той же папке, где лежит датасет, и импортируем сразу две библиотеки: одну для работы с данными, а вторую — для визуализации:

# добавляем библиотеку для анализа датасета
import pandas as pd

# и библиотеку для визуализации
import matplotlib.pyplot as plt

Считаем файл с записями и сразу убедимся, что данные подгрузились правильно. Для этого выведем первые и последние 5 записей. Первые нам нужны для проверки, а последние — чтобы убедиться, что в датасете нет в конце мусорных или лишних служебных данных:

# считываем файл с записями
uber_df= pd.read_csv("uber-raw-data-sep14.csv")

# выводим первые 5 записей, чтобы убедиться, что файл считался правильно
print(uber_df.head(5))

# смотрим на последние 5 записей 
print(uber_df.tail())
Бигдата и такси: как найти самое нагруженное время

После запуска кода в консоли появляются два списка — начало и конец датасета. Видно, что данные хранятся в одном и том же формате и под конец датасета не происходит ничего критичного — всё то же самое, что и в начале. Это значит, что с таким набором данных можно двигаться дальше.

Ещё мы узнали, как называется каждый столбец, — это нам пригодится на следующем этапе, когда мы будем переделывать весь датасет.

Подготавливаем данные

Чтобы программа смогла проанализировать данные и построить графики, нам нужно привести дату и время в стандартный вид: преобразовать её в формат datetime, из которого легко извлекать часы, минуты и дни.

Чтобы это сделать, используем команду .to_datetime():

# переводим дату и время из строки в стандартный формат для даты
uber_df['Date/Time']= pd.to_datetime(uber_df['Date/Time'])

Теперь мы можем использовать все преимущества нового формата и выделить оттуда отдельно в новые колонки:

  • день,
  • час,
  • день недели.

Эти данные мы будем использовать для анализа и визуализации.

# получаем день заказа из стандартной даты и кладём его в новую колонку
uber_df["Day"] = uber_df["Date/Time"].apply(lambda x: x.day)
# точно так же получаем час
uber_df["Hour"] = uber_df["Date/Time"].apply(lambda x: x.hour)
# и номер дня недели
uber_df["Weekday"] = uber_df["Date/Time"].apply(lambda x: x.weekday())
# выводим первые 5 записей в новой таблице
print(uber_df.head(5))
Бигдата и такси: как найти самое нагруженное время

Таблица явно изменилась: в конце появились три новые колонки с номером дня, часа и порядковым номером дня недели. Если интересно, почему день недели начинается с нуля, — почитайте нашу статью про нумерацию в компьютере.

Визуализируем данные

У нас всё готово для того, чтобы представить эти данные в понятной форме — например в виде картинок и графиков.

Начнём с распределения по дням недели — построим график и посмотрим, в какие числа вызывают такси чаще всего. Чтобы это сделать, нам нужно:

  1. Подготовить холст — виртуальный макет, где будет располагаться картинка.
  2. Нарисовать гистограмму — специальный график, который состоит из небольших столбиков. Чем выше столбик — тем больше вызовов.
  3. Подписать оси — так будет понятно, что происходит на картинке.
  4. Сохранить изображение в файл.

Сделаем это всё сразу и подпишем комментариями каждый фрагмент кода:

# Делаем визуализацию распределения вызовов в зависимости от дня в месяце
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по дням
plt.hist(uber_df.Day, width= 0.6, bins= 30)
# подписываем оси
plt.title("Распределение вызовов в течение месяца", fontsize=16)
plt.xlabel("День", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('day.png', dpi=120)
Бигдата и такси: как найти самое нагруженное время

На графике явно видна какая-то динамика — есть повторяющиеся спады и подъёмы спроса на такси. Причём если посчитать дни недели (а первое число в датасете — это понедельник), то увидим, что спрос растёт к концу недели, а потом резко падает. Можно сделать первоначальный вывод, что с пятницы по воскресенье у нас будет повышенный спрос, а значит, хорошо бы, чтобы в это время в городе было больше водителей, чем в понедельник.

Чтобы это проверить, посмотрим на распределение количества вызовов по дням недели, где 0 это понедельник, а 6 — воскресенье:

# Делаем визуализацию распределения вызовов в зависимости от дня недели
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по дням недели
plt.hist(uber_df.Weekday, width= 0.6, range= (0, 6.5), bins=7, color= "green")
# подписываем оси
plt.title("Распределение вызовов по дням недели", fontsize=16)
plt.xlabel("День недели", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('weekday.png', dpi=120)
Бигдата и такси: как найти самое нагруженное время

А вот тут картина уже другая: мы видим рост спроса к выходным, но в воскресенье он внезапно становится ниже. Получается, что нам нужно скорректировать предыдущий вывод и планировать высокую нагрузку только на пятницу и субботу.

Ещё заметен внезапный всплеск спроса во вторник. С чем он связан — это уже должны думать аналитики. 

Напоследок посмотрим на распределение вызовов по часам:

# Делаем визуализацию распределения вызовов в течение суток
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по часам
plt.hist(uber_df.Hour, width= 0.6, bins=24, color= "orange")
# подписываем оси
plt.title("Распределение вызовов по часам", fontsize=16)
plt.xlabel("Часы", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('hours.png', dpi=120)
Бигдата и такси: как найти самое нагруженное время

Тут очевидный всплеск с утра, когда все хотят попасть на работу, а с 15:00 начинается вторая волна — деловые поездки, которые плавно переходят в режим «добраться до дома». Это значит, что водителю проще всего получить заказ с 15 до 21 часа.

Что можно сделать ещё

Вот какие данные можно ещё достать из этого датасета:

  • в какой день недели какие часы самые свободные, а какие — загруженные;
  • в какой район больше всего вызовов и когда;
  • на каком участке больше всего вызовов;
  • есть ли зависимость между номером участка и количеством вызовов в разное время;
  • самое удачное время для водителя (когда больше всего заказов);
  • самое удачное время для клиентов (когда больше вероятность быстро вызвать свободную машину).

И всё это делается несколькими выражениями в Python, применёнными к библиотеке для визуализации данных. 

Вот так дата-сайентисты и работают. И за это платят.

# добавляем библиотеку для анализа датасета
import pandas as pd 

# и библиотеку для визуализации
import matplotlib.pyplot as plt

# считываем файл с записями
uber_df= pd.read_csv("uber-raw-data-sep14.csv")

# выводим первые 5 записей, чтобы убедиться, что файл считался правильно
print(uber_df.head(5))

# смотрим на последние 5 записей 
print(uber_df.tail())

# переводим дату и время из строки в стандартный формат для даты
uber_df['Date/Time']= pd.to_datetime(uber_df['Date/Time'])

# получаем день заказа из стандартной даты и кладём его в новую колонку
uber_df["Day"] = uber_df["Date/Time"].apply(lambda x: x.day)
# точно так же получаем час
uber_df["Hour"] = uber_df["Date/Time"].apply(lambda x: x.hour)
# и номер дня недели
uber_df["Weekday"] = uber_df["Date/Time"].apply(lambda x: x.weekday())
# выводим первые 5 записей в новой таблице
print(uber_df.head(5))

# Делаем визуализацию распределения вызовов в зависимости от дня в месяце
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по дням
plt.hist(uber_df.Day, width= 0.6, bins= 30)
# подписываем оси
plt.title("Распределение вызовов в течение месяца", fontsize=16)
plt.xlabel("День", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('day.png', dpi=120)

# Делаем визуализацию распределения вызовов в зависимости от дня недели
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по дням недели
plt.hist(uber_df.Weekday, width= 0.6, range= (0, 6.5), bins=7, color= "green")
# подписываем оси
plt.title("Распределение вызовов по дням недели", fontsize=16)
plt.xlabel("День недели", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('weekday.png', dpi=120)


# Делаем визуализацию распределения вызовов в течение суток
# готовим холст
fig,ax = plt.subplots(figsize = (12,6))
# строим гистограмму распределения по часам
plt.hist(uber_df.Hour, width= 0.6, bins=24, color= "orange")
# подписываем оси
plt.title("Распределение вызовов по часам", fontsize=16)
plt.xlabel("Часы", fontsize=14)
plt.ylabel("Плотность вызовов", fontsize=14)
# сохраняем картинку
plt.savefig('hours.png', dpi=120)

Рекламная интеграция

Чтобы научиться делать правильные выводы из бигдаты, приходите в Практикум на курсы «Аналитик данных». Если надо побыстрее — приходите на буткемп: объём примерно тот же, но занятия вдвое интенсивнее.

Текст:

Михаил Полянин

Редактор:

Максим Ильяхов

Художник:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Кирилл Климентьев

Соцсети:

Виталий Вебер

Данные — это новая нефть
А аналитики данных — новая элита ИТ. Эти люди помогают понять огромные массивы данных и принять правильные решения. Изучите профессию аналитика и начните карьеру в ИТ: старт — бесплатно, а после обучения — помощь с трудоустройством.
Начать качать
Данные — это новая нефть Данные — это новая нефть Данные — это новая нефть Данные — это новая нефть
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
Как убрать что угодно на любом сайте
Как убрать что угодно на любом сайте

Самый популярный приём разработчиков.

easy
Вжух, вжух! Добавляем звук меча на любой странице

Время дурацких проектов.

medium
Улучшаем автоматизацию новостей
Улучшаем автоматизацию новостей

И получаем готовый рабочий продукт.

easy
Делаем свой удалённый доступ к компьютеру
Делаем свой удалённый доступ к компьютеру

Ставим RustDesk на компьютер и сервер

medium
Как поймать баг в коде: отладка в браузере
Как поймать баг в коде: отладка в браузере

Вместо тысячи console.log();

easy
Простейший генератор креативного текста

Без нейросетей, регистрации и СМС.

hard
глитч-эффект
Проглючило: делаем глитч-эффект на SASS

На это можно смотреть бесконечно.

medium
Cортировка подсчётом: как работает сортировка без сравнений
Cортировка подсчётом: как работает сортировка без сравнений

Надо просто посчитать, сколько раз встречается каждый элемент

medium
Пианино на JavaScript для Chrome
Пианино на JavaScript для Chrome

Не «Мир Дикого запада», но тоже сгодится.

medium
Что означает ошибка TypeError: something() takes 0 positional arguments but 1 was given
Что означает ошибка TypeError: something() takes 0 positional arguments but 1 was given

Это когда аргументы появляются там, где их быть не должно

easy
hard