Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Васильев Ю. - Python для data science (Библиотека программиста) - 2023.pdf
Скачиваний:
10
Добавлен:
07.04.2024
Размер:
7.21 Mб
Скачать

204      Глава 9. Анализ данных о местоположении

В скрипте используется как Shapely, так и geopy. Сначала задаем объект Shapely Polygon, включающий местоположение пассажира, как мы делали ранее . Аналогично задаем объекты Point для автомобиля, места подачи и пункта проезда . Затем вычисляем расстояние в метрах с помощью функции geopy distance(). Если такси находится внутри многоугольника, находим расстояние непосредственно между такси и местом подачи . А если нет, то сначала вычисляем расстояние между машиной и пунктом проезда, а затем расстояние между этим пунктом и местом подачи. Складывая их, получаем общее расстояние :

1544

УПРАЖНЕНИЕ № 15: СОВЕРШЕНСТВОВАНИЕ АЛГОРИТМА ПОДБОРА МАШИНЫ

В скрипте выше мы обработали данные о местоположении лишь одного автомобиля, определив расстояние между ним и местом подачи. Измените скрипт таким образом, чтобы он вычислял расстояния между местом посадки и каждой машиной. Для этого объедините точки, представляющие такси, в список, а затем пройдите по этому списку в цикле, используя в теле блоки if/else из предыдущего скрипта. Затем определите ближайший к месту подачи автомобиль.

Объединение пространственных

и непространственных данных

До сих пор в этой главе мы работали исключительно с пространственными данными, но важно понимать, что пространственный анализ часто требует учета и непространственных данных. Например, какой смысл от информации о том, что магазин находится в 16 километрах от текущего местоположения, если мы не уверены, что в нем есть нужный товар? Или, возвращаясь к примеру с такси, что нам даст возможность определить ближайшую машину к месту посадки, если мы не знаем, доступна она или же водитель выполняет другой заказ? В этом разделе мы рассмотрим, как учитывать непространственные данные в рамках пространственного анализа.

Получение непространственных характеристик

Информацию о доступности такси можно получить из датасета, содержащего заказы поездок. Как только на автомобиль будет назначен заказ, можно поместить

Объединение пространственных и непространственных данных      205

эту информацию в структуру данных orders, где будет указываться заказ и его статус: открытый (open) — в процессе либо закрытый (closed) — завершенный. Согласно этой схеме, отфильтровав открытые заказы, мы поймем, какие автомобили недоступны для выполнения нового заказа. Вот как реализовать эту логику в Python:

import pandas as pd orders = [

('order_039', 'open', 'cab_14'), ('order_034', 'open', 'cab_79'), ('order_032', 'open', 'cab_104'), ('order_026', 'closed', 'cab_79'), ('order_021', 'open', 'cab_45'), ('order_018', 'closed', 'cab_26'), ('order_008', 'closed', 'cab_112')

]

df_orders = pd.DataFrame(orders, columns =['order','status','cab']) df_orders_open = df_orders[df_orders['status']=='open'] unavailable_list = df_orders_open['cab'].values.tolist() print(unavailable_list)

Список кортежей orders, используемый в этом примере, можно получить из более полного датасета, например коллекции всех заказов, открытых за последние два часа, которая включает дополнительную информацию о каждом заказе (место подачи, место высадки, время начала, время окончания и т. д.). Для простоты здесь датасет уже сокращен до полей, необходимых для текущей задачи. Мы преобразуем список в объект DataFrame, затем фильтруем его, чтобы включить только заказы со статусом open. Наконец, преобразуем DataFrame в список, содержащий только значения из столбца cab. Список недоступных такси выглядит следующим образом:

['cab_14', 'cab_79', 'cab_104', 'cab_45']

Вооружившись этим списком, проверим другие автомобили и определим, какой из них находится ближе всего к месту подачи. Добавим этот код к предыдущему скрипту:

from geopy.distance import distance pick_up = 46.083822, 38.967845 cab_26 = 46.073852, 38.991890 cab_112 = 46.078228, 39.003949 cab_104 = 46.071226, 39.004947

206      Глава 9. Анализ данных о местоположении

cab_14 = 46.004859, 38.095825 cab_79 = 46.088621, 39.033929 cab_45 = 46.141225, 39.124934

cabs = {'cab_26': cab_26, 'cab_112': cab_112, 'cab_14': cab_14, 'cab_104': cab_104, 'cab_79': cab_79, 'cab_45': cab_45}

dist_list = []

for cab_name, cab_loc in cabs.items(): if cab_name not in unavailable_list: dist = distance(pick_up, cab_loc).m

dist_list.append((cab_name, round(dist)))

print(dist_list)

print(min(dist_list, key=lambda x: x[1]))

Для демонстрации вручную определяем геокоординаты места подачи и всех машин в виде кортежей и передаем их в словарь, где ключами являются названия такси. Затем проходим по словарю и для каждого автомобиля, не входящего в unavailable_list, используем geopy для вычисления расстояния до места подачи. Наконец, выводим на экран весь список доступных такси с указанием расстояния до места подачи, а также ближайший автомобиль:

[('cab_26', 2165), ('cab_112', 2861)] ('cab_26', 2165)

В данном примере cab_26 — ближайший доступный автомобиль.

УПРАЖНЕНИЕ № 16:

ФИЛЬТРАЦИЯ ДАННЫХ С ПОМОЩЬЮ СПИСКОВОГО ВКЛЮЧЕНИЯ

В предыдущем разделе мы отфильтровали список orders так, чтобы остались лишь недоступные машины, предварительно преобразовав orders в DataFrame. Теперь попробуйте сгенерировать список unavailable_list, не используя pandas; вместо этого примените списковые включения. При таком подходе вы сможете получать список такси, назначенных на открытые заказы, одной строкой кода:

unavailable_list = [x[2] for x in orders if x[1] == 'open']

Вам не придется ничего менять в остальной части скрипта.

Объединение пространственных и непространственных данных      207

Объединение датасетов с пространственными и непространственными данными

В предыдущем примере мы хранили пространственные данные (местоположение каждого такси) и непространственные данные (доступные такси) в отдельных структурах данных. Однако иногда выгодно объединить пространственные и непространственные данные в одну структуру.

Учитывайте, что для назначения автомобиля на заказ кроме доступности может потребоваться проверка некоторых других условий. Например, клиенту может понадобиться такси с детским креслом. Чтобы найти нужную машину, необходимо использовать датасет, который включает непространственную информацию о машине, а также расстояние от каждого автомобиля до места подачи. Для вышеупомянутого случая можно использовать датасет, содержащий всего два столбца: название такси и наличие детского кресла. Вот как его создать:

cabs_list = [ ('cab_14',1), ('cab_79',0), ('cab_104',0), ('cab_45',1), ('cab_26',0), ('cab_112',1)

]

В машинах, для которых указано значение 1 во второй колонке, есть детское кресло. Затем мы преобразуем список в датафрейм. Мы также создаем второй датафрейм из dist_list, списка доступных такси и их расстояния до места подачи, который мы сформировали в предыдущем разделе:

df_cabs = pd.DataFrame(cabs_list, columns =['cab', 'seat']) df_dist = pd.DataFrame(dist_list, columns =['cab', 'dist'])

Теперь объединяем эти датафреймы по столбцу cab:

df = pd.merge(df_cabs, df_dist, on='cab', how='inner')

Используем inner join, то есть объединяем только такси, которые есть и в df_cabs, и в df_dist. На практике, поскольку df_distсодержит только доступные на текущий момент автомобили, недоступные машины будут исключены из итогового датасета. Теперь объединенный датафрейм включает как пространственные