Сегодня будет простой проект с бигдатой на 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))
Таблица явно изменилась: в конце появились три новые колонки с номером дня, часа и порядковым номером дня недели. Если интересно, почему день недели начинается с нуля, — почитайте нашу статью про нумерацию в компьютере.
Визуализируем данные
У нас всё готово для того, чтобы представить эти данные в понятной форме — например в виде картинок и графиков.
Начнём с распределения по дням недели — построим график и посмотрим, в какие числа вызывают такси чаще всего. Чтобы это сделать, нам нужно:
- Подготовить холст — виртуальный макет, где будет располагаться картинка.
- Нарисовать гистограмму — специальный график, который состоит из небольших столбиков. Чем выше столбик — тем больше вызовов.
- Подписать оси — так будет понятно, что происходит на картинке.
- Сохранить изображение в файл.
Сделаем это всё сразу и подпишем комментариями каждый фрагмент кода:
# Делаем визуализацию распределения вызовов в зависимости от дня в месяце
# готовим холст
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)
Рекламная интеграция
Чтобы научиться делать правильные выводы из бигдаты, приходите в Практикум на курсы «Аналитик данных». Если надо побыстрее — приходите на буткемп: объём примерно тот же, но занятия вдвое интенсивнее.