Список постижений являются очень неэффективными способ иметь дело с массивами numpy. Они являются особенно плохим выбором для расчета расстояния.
Чтобы найти разницу между данными и точкой, вы должны просто сделать data - point
. Затем вы можете рассчитать расстояние, используя np.hypot
, или, если хотите, поместите квадрат, суммируйте его и возьмите квадратный корень.
Это немного проще, если вы сделаете его массивом Nx2 для целей расчета.
В принципе, вы хотите что-то вроде этого:
import numpy as np
data = np.array([[[1704, 1240],
[1745, 1244],
[1972, 1290],
[2129, 1395],
[1989, 1332]],
[[1712, 1246],
[1750, 1246],
[1964, 1286],
[2138, 1399],
[1989, 1333]],
[[1721, 1249],
[1756, 1249],
[1955, 1283],
[2145, 1399],
[1990, 1333]]])
point = [1989, 1332]
#-- Calculate distance ------------
# The reshape is to make it a single, Nx2 array to make calling `hypot` easier
dist = data.reshape((-1,2)) - point
dist = np.hypot(*dist.T)
# We can then reshape it back to AxBx1 array, similar to the original shape
dist = dist.reshape(data.shape[0], data.shape[1], 1)
print dist
Это дает:
array([[[ 299.48121811],
[ 259.38388539],
[ 45.31004304],
[ 153.5219854 ],
[ 0. ]],
[[ 290.04310025],
[ 254.0019685 ],
[ 52.35456045],
[ 163.37074401],
[ 1. ]],
[[ 280.55837182],
[ 247.34186868],
[ 59.6405902 ],
[ 169.77926846],
[ 1.41421356]]])
Теперь, убрав ближайший элемент является немного сложнее, чем просто получать ближайший элемент.
С помощью numpy вы можете использовать булево индексирование, чтобы сделать это довольно легко.
Однако вам нужно немного беспокоиться о выравнивании ваших осей.
Ключ должен понимать, что операции «трансляции» в режиме «широковещания» выполняются по оси последней. В этом случае мы хотим бродить по средней оси.
Также -1
может использоваться в качестве заполнителя для размера оси. Numpy рассчитает допустимый размер, если -1
помещается как размер оси.
Что мы должны сделать, будет выглядеть немного так:
#-- Remove closest point ---------------------
mask = np.squeeze(dist) != dist.min(axis=1)
filtered = data[mask]
# Once again, let's reshape things back to the original shape...
filtered = filtered.reshape(data.shape[0], -1, data.shape[2])
Вы могли бы сделать, что одна линия, я просто разбив его для удобства чтения. Ключ состоит в том, что dist != something
дает булевский массив, который затем можно использовать для индексации исходного массива.
Итак, Собираем все вместе:
import numpy as np
data = np.array([[[1704, 1240],
[1745, 1244],
[1972, 1290],
[2129, 1395],
[1989, 1332]],
[[1712, 1246],
[1750, 1246],
[1964, 1286],
[2138, 1399],
[1989, 1333]],
[[1721, 1249],
[1756, 1249],
[1955, 1283],
[2145, 1399],
[1990, 1333]]])
point = [1989, 1332]
#-- Calculate distance ------------
# The reshape is to make it a single, Nx2 array to make calling `hypot` easier
dist = data.reshape((-1,2)) - point
dist = np.hypot(*dist.T)
# We can then reshape it back to AxBx1 array, similar to the original shape
dist = dist.reshape(data.shape[0], data.shape[1], 1)
#-- Remove closest point ---------------------
mask = np.squeeze(dist) != dist.min(axis=1)
filtered = data[mask]
# Once again, let's reshape things back to the original shape...
filtered = filtered.reshape(data.shape[0], -1, data.shape[2])
print filtered
Урожайность:
array([[[1704, 1240],
[1745, 1244],
[1972, 1290],
[2129, 1395]],
[[1712, 1246],
[1750, 1246],
[1964, 1286],
[2138, 1399]],
[[1721, 1249],
[1756, 1249],
[1955, 1283],
[2145, 1399]]])
На стороне записки, если более чем один пункт одинаково близко, это не будет работать. Массивные массивы должны иметь одинаковое количество элементов вдоль каждого измерения, поэтому в этом случае вам нужно будет повторно выполнить группировку.
А как-то я не видел этого, прежде чем отправил. Я думал об использовании 'apply_along_axis', но я тестировал его, и это намного быстрее. – senderle
'apply_along_axis' должно использовать меньше памяти, поэтому оба подхода по-прежнему полезны! –
Спасибо! Очень краткий, но информативный. Так быстро, тоже. – OneTrickyPony