Матрица расстояний между двумя точечными слоями - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть два массива, содержащие координаты точки как shapely.geometry.Point с разными размерами.

Например:

[Point(X Y), Point(X Y)...]
[Point(X Y), Point(X Y)...]

Я хотел бы создать «перекрестное произведение» из этих двухмассивы с функцией расстояния. Функция расстояния от shapely.geometry, которая является простым вычислением расстояния вектора геометрии. Я пытаюсь создать матрицу расстояний между точками M: N:

enter image description here

Сейчас у меня есть эта функция:

    source = gpd.read_file(source)
    near = gpd.read_file(near)

    source_list = source.geometry.values.tolist()
    near_list = near.geometry.values.tolist()

    array = np.empty((len(source.ID_SOURCE), len(near.ID_NEAR)))

    for index_source, item_source in enumerate(source_list):
        for index_near, item_near in enumerate(near_list):
            array[index_source, index_near] = item_source.distance(item_near)

    df_matrix = pd.DataFrame(array, index=source.ID_SOURCE, columns = near.ID_NEAR)

Который делает работу хорошо, но медленно. 4000 x 4000 баллов - это около 100 секунд (у меня есть наборы данных, которые намного больше, поэтому скорость является основной проблемой). Я хотел бы избежать этой двойной петли, если это возможно. Я попытался сделать в панде данные, как в (который имеет ужасную скорость):

for index_source, item_source in source.iterrows():
         for index_near, item_near in near.iterrows():
             df_matrix.at[index_source, index_near] = item_source.geometry.distance(item_near.geometry)

Немного быстрее (но все еще в 4 раза медленнее, чем numpy):

    for index_source, item_source in enumerate(source_list):
        for index_near, item_near in enumerate(near_list):
             df_matrix.at[index_source, index_near] = item_source.distance(item_near)

Есть либолее быстрый способ сделать это? Я думаю, что есть, но я не знаю, как поступить. Возможно, мне удастся разбить блок данных на более мелкие части и отправить фрагмент на другое ядро ​​и объединить результаты - это последнее средство. Если каким-то образом мы сможем использовать NumPy только с некоторой магией индексирования, я могу отправить ее в GPU и покончить с этим в самое короткое времяНо двойного цикла пока нет. Также я не хотел бы использовать какую-либо другую библиотеку, кроме Pandas / Numpy. Я могу использовать обработку SAGA и модуль Point points (http://www.saga -gis.org / saga_tool_doc / 2.2.2 / shape_points_3.html ), который чертовски быстр, но я ищу решение только для Python.

1 Ответ

1 голос
/ 05 ноября 2019

Если вы можете получить координаты в отдельных векторах, я бы попробовал это:

import numpy as np

x = np.asarray([5.6, 2.1, 6.9, 3.1]) # Replace with data
y = np.asarray([7.2, 8.3, 0.5, 4.5]) # Replace with data

x_i = x[:, np.newaxis]
x_j = x[np.newaxis, :]

y_i = y[:, np.newaxis]
y_j = y[np.newaxis, :]

d = (x_i-x_j)**2+(y_i-y_j)**2

np.sqrt(d, out=d)
...