<jupyter_start><jupyter_text>ВводныеВодитель может находиться в 4 возможных статусах:    * free -- доступен для нового заказа    * enroute -- едет на заказ    * ontrip -- выполняет заказ    * busy -- недоступен для нового заказаВозможные переходы из одного состояние в другое определены как:    * free -> [free, enroute, busy]    * enroute -> [free, ontrip]    * ontrip -> [free]    * busy -> [free]Почему переходы определяются таким образом:1. Из состояния free можно перейти в    * free -- если водитель ушел в офлайн и заново вышел на линию, тогда подряд будет две записи со статусом free    * enroute -- если водитель принял заказ, то переходит в статус enroute и едет к клиенту    * busy -- если водитель нажал кнопку "Занят" в таксометре (пошел на обед и т.д.)2. Из состояния enroute можно перейти в     * free -- если клиент или водитель отменил заказ    * ontrip -- если водитель приехал к клиенту и начал выполнять заказ3. Из состояния ontrip можно перейти только в free (после выполнения заказа)4. Из состояния 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).<jupyter_code>def neighbors(iterable):
    # Write generator function which yields 
    # previous, current and next values in iterable list.
    # ... type your code here ...
# Check if test passes
def test_neighbors():
    test_neighbors = neighbors( range(2) )
    assert test_neighbors.next() == (None, 0, 1)

test_neighbors()<jupyter_output><empty_output><jupyter_text>2. Сгруппировать данные на уровне водителя таким образом, чтобы в одной строке находились все его записи со статусами и началом статуса списком: Формат исходной таблицы:driver_idstatusdttm9f8f9bf3ee8f4874873288c246bd2d05free2018-02-04 00:199f8f9bf3ee8f4874873288c246bd2d05busy2018-02-04 01:038f174ffd446c456eaf3cca0915d0368dfree2018-02-03 15:438f174ffd446c456eaf3cca0915d0368denroute2018-02-03 17:02......... Формат сгруппированной таблицы:driver_iddriver_info9f8f9bf3ee8f4874873288c246bd2d05[("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) ...]<jupyter_code>df = pd.read_csv(".../dataset.csv", parse_dates=["dttm"])
# ... type your code here ...<jupyter_output><empty_output><jupyter_text>3. Используя функцию neighbors, написать функцию, которая для каждой записи в списке driver_info посчитает ее длительность.<jupyter_code>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
# 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()
df["driver_info"] = df.driver_info.apply(calc_status_duration)<jupyter_output><empty_output><jupyter_text>4. Используя функцию neighbors, написать функцию, которая сформирует из списка driver_info список поездок с информацией о длительности поездки и эффективности (duration_ontrip, efficiency).<jupyter_code>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 ...
# 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()
df["driver_info"] = df.driver_info.apply(collapse_statuses)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1018501557061733, 'fraction_numerical': 0.07437259571350065, 'mean_word_length': 3.6987951807228914, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '531511', 'license': 'MIT', 'n_tokens_mistral': 2240, 'n_tokens_neox': 2168, 'n_words': 538, 'path': 'test_task_python-Copy1.ipynb', 'repo_name': 'alekz112/Test', 'size': '5459'}