Выполнение расчетов с несколькими массивами numpy без циклов for - PullRequest
0 голосов
/ 13 апреля 2019

Я грубой силой вычисляю кратчайшее расстояние от одной точки до многих других на 2D-плоскости, используя данные, поступающие с кадров данных панд с использованием df['column'].to_numpy().

В настоящее время я делаю это, используя вложенные циклы for на массивах numpy, чтобы заполнить список, принимая минимальное значение этого списка и сохраняя это значение в другом списке.

Проверка 1000 баллов (от df_point) против 25 000 (от df_compare) занимает около одной минуты, поскольку это, понятно, неэффективный процесс. Мой код ниже.

point_x = df_point['x'].to_numpy()
compare_x = df_compare['x'].to_numpy()
point_y = df_point['y'].to_numpy()
compare_y = df_compare['y'].to_numpy()
dumarr = []
minvals = []

# Brute force caclulate the closet point by using the Pythagorean theorem comparing each
# point to every other point
for k in range(len(point_x)):
    for i,j in np.nditer([compare_x,compare_y]):
        dumarr.append(((point_x[k] - i)**2 + (point_y[k] - j)**2))
    minval.append(df_compare['point_name'][dumarr.index(min(dumarr))])
    # Clear dummy array (otherwise it will continuously append to)
    dumarr = []

Это не особенно питонический. Есть ли способ сделать это с помощью векторизации или, по крайней мере, без использования вложенных циклов for?

Ответы [ 4 ]

1 голос
/ 13 апреля 2019

Подход состоит в том, чтобы создать матрицу 1000 x 25000, а затем найти индексы минимумов строк.

# distances for all combinations (1000x25000 matrix)
dum_arr = (point_x[:, None] - compare_x)**2 + (point_y[:, None] - compare_y)**2

# indices of minimums along rows
idx = np.argmin(dum_arr, axis=1)

# Not sure what is needed from the indices, this get the values 
# from `point_name` dataframe using found indices
min_vals = df_compare['point_name'].iloc[idx]
0 голосов
/ 13 апреля 2019

Вот пример использования scipy cdist, который идеально подходит для этого типа проблемы:

import numpy as np
from scipy.spatial.distance import cdist

point = np.array([[1, 2], [3, 5], [4, 7]])
compare = np.array([[3, 2], [8, 5], [4, 1], [2, 2], [8, 9]])

# create 3x5 distance matrix
dm = cdist(point, compare)
# get row-wise mins
mins = dm.min(axis=1)
0 голосов
/ 13 апреля 2019

Я собираюсь дать вам подход:

  1. Создать DataFrame со столбцами: -> pointID, CoordX, CoordY
  2. Создать вторичный DataFrame со значением смещения 1 (oldDF.iloc [pointIDx] = newDF.iloc [pointIDx] -1)
  3. Это значение смещения необходимо зациклить от 1 до количества координат-1
  4. tempDF ["Euclid Dist"] = sqrt (square (oldDf ["CoordX"] - newDF ["CoordX"]) + square (oldDf ["CoordY"] - newDF ["CoordY"]))
  5. Добавить этот tempDF в список

Причины, по которым это будет быстрее:

  1. Только один цикл для итерации смещения от 1 до количества координат-1
  2. Векторизация позаботиласьотключить шаг 4
  3. Использовать функции квадратного корня и квадрата для получения наилучших результатов
0 голосов
/ 13 апреля 2019

Вместо того, чтобы найти самую близкую точку, вы можете попробовать найти самую близкую в направлении x и y отдельно, а затем сравнить эти две, чтобы найти, что ближе, используя встроенную функцию min, как верхний ответ из этого вопроса. :

min(myList, key=lambda x:abs(x-myNumber))

из списка целых чисел, получить число, ближайшее к данному значению

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

for k,m in np.nditer([point_x, point_y]): min = min(compare_x, compare_y, key=lambda x,y: (x-k)**2 + (y-m)**2 )

Другой альтернативой может быть предварительное вычисление расстояния от (0,0) или другой точки, например (-1000,1000), для всех точек в массиве сравнения, сортировка массива сравнения на основе этого, затем только контрольные точки с аналогичным расстоянием от эталона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...