In [ ]:
%matplotlib inline
import pandas as pd
import seaborn as sns
from datetime import datetime
Вводные
Водитель может находиться в 4 возможных статусах:
* free -- доступен для нового заказа
* enroute -- едет на заказ
* ontrip -- выполняет заказ
* busy -- недоступен для нового заказа
Возможные переходы из одного состояние в другое определены как:
* free -> [free, enroute, busy]
* enroute -> [free, ontrip]
* ontrip -> [free]
* busy -> [free]
Почему переходы определяются таким образом:
Эффективность на поездке -- это время с клиентом в машине (ontrip), деленное на сумму длительностей всех статусов, связанных с поездкой (sum(free) + enroute + ontrip), где sum(free) -- время простоя.
Время простоя -- это сумма всех статусов free, предшествующих поездке. Суммируются все статусы free, идущие подряд, а также те, которые были прерваны короткими статусами busy или enroute (короткий статус == меньше какого-то TIMEOUT'а).
Имеется набор данных со статусами водителей, по которому необходимо построить зависимость длительности поездки от эффективности.
* driver_id -- id водителя
* status -- один из статусов
* dttm -- время начала статуса
Примечания:
* Поездка считается только при наличии статуса ontrip
* Тесты написаны для python 2
1. Написать функцию-генератор, которая будет отдавать соседние элементы в цикле. Функция понадобится для итерирования по записям водителя и проверки соседних статусов по условиям. Не забудьте проверить, что тесты проходят без ошибок (см. test_neighbors).
In [ ]:
def neighbors(iterable):
# Write generator function which yields
# previous, current and next values in iterable list.
# ... type your code here ...
In [ ]:
# Check if test passes
def test_neighbors():
test_neighbors = neighbors( range(2) )
assert test_neighbors.next() == (None, 0, 1)
test_neighbors()
2. Сгруппировать данные на уровне водителя таким образом, чтобы в одной строке находились все его записи со статусами и началом статуса списком:
Формат исходной таблицы:
driver_id | status | dttm |
9f8f9bf3ee8f4874873288c246bd2d05 | free | 2018-02-04 00:19 |
9f8f9bf3ee8f4874873288c246bd2d05 | busy | 2018-02-04 01:03 |
8f174ffd446c456eaf3cca0915d0368d | free | 2018-02-03 15:43 |
8f174ffd446c456eaf3cca0915d0368d | enroute | 2018-02-03 17:02 |
... | ... | ... |
Формат сгруппированной таблицы:
driver_id | driver_info |
9f8f9bf3ee8f4874873288c246bd2d05 | [("free", 2018-02-04 00:19), ("busy", 2018-02-04 01:03)] |
8f174ffd446c456eaf3cca0915d0368d | [("free", 2018-02-03 15:43), ("enroute", 2018-02-03 17:02) ...] |
In [ ]:
df = pd.read_csv(".../dataset.csv", parse_dates=["dttm"])
# ... type your code here ...
3. Используя функцию neighbors, написать функцию, которая для каждой записи в списке driver_info посчитает ее длительность.
In [ ]:
def calc_status_duration(driver_info):
driver_info_updated = []
for i, j, k in neighbors(driver_info):
# ... type your code here ...
return driver_info_updated
In [ ]:
# Check if test passes
def test_calc_status_duration():
sample_driver_info = [("free", datetime(2018, 4, 2, 0, 19)),
("busy", datetime(2018, 4, 2, 1, 3)),]
sample_driver_info_updated = [('free', datetime(2018, 4, 2, 0, 19), 2640.0),
('busy', datetime(2018, 4, 2, 1, 3), None),]
assert calc_status_duration(sample_driver_info) == sample_driver_info_updated
test_calc_status_duration()
In [ ]:
df["driver_info"] = df.driver_info.apply(calc_status_duration)
4. Используя функцию neighbors, написать функцию, которая сформирует из списка driver_info список поездок с информацией о длительности поездки и эффективности (duration_ontrip, efficiency).
In [ ]:
TIMEOUT = 1600
def collapse_statuses(driver_info):
# Here define conditions under which the "free" state
# should be attributed to the trip.
# ... type your code here ...
In [ ]:
# Check if test passes
def test_collapse_statuses():
sample_driver_info = [("free", datetime(2018, 4, 2, 0, 19), 2640.0),
("busy", datetime(2018, 4, 2, 1, 3), 1660.0),
("free", datetime(2018, 4, 2, 1, 30, 40), 2050.0),
("enroute", datetime(2018, 4, 2, 2, 4, 50), 70.0),
("free", datetime(2018, 4, 2, 2, 6), 500.0),
("enroute", datetime(2018, 4, 2, 2, 14, 20), 520.0),
("ontrip", datetime(2018, 4, 2, 2, 23), 3060.0),
("free", datetime(2018, 4, 2, 3, 14), None)
]
sample_driver_info_updated = [(3060.0, 3060.0 / (3060.0 + 520.0 + 500.0 + 2050.0))]
assert collapse_statuses(sample_driver_info) == sample_driver_info_updated
test_collapse_statuses()
In [ ]:
df["driver_info"] = df.driver_info.apply(collapse_statuses)
5. Нарисовать и проинтерпретировать зависимость между длительностью поездки и эффективностью.
Подсказка: требуется сделать обратное преобразование из таблицы со строками на уровне водителя в таблицу со строками на уровне поездки.
In [ ]: