Сложность с бесшумной трансляцией - PullRequest
1 голос
/ 10 июня 2019

У меня есть два двумерных облака точек (oldPts и newPts), которые я хочу объединить. Это массивы mx2 и nx2 numpyinteger с m и n порядка 2000. newPts содержит много дубликатов или почти дубликатов oldPts, и мне нужно удалить их перед объединением.

До сих пор я использовал функцию histogram2d для получения 2d представления oldPts (H). Затем я сравниваю каждый newPt с NxN-областью H, и если он пуст, я принимаю точку. Эту последнюю часть я сейчас делаю с циклом Python, который я хотел бы удалить. Кто-нибудь может показать мне, как сделать это с помощью трансляции, или, возможно, предложить совершенно другой метод решения проблемы. рабочий код ниже

npzfile = np.load(path+datasetNo+'\\temp.npz')
arrs = npzfile.files
oldPts = npzfile[arrs[0]]
newPts = npzfile[arrs[1]]

# remove all the negative values 
oldPts = oldPts[oldPts.min(axis=1)>=0,:]
newPts = newPts[newPts.min(axis=1)>=0,:]

# round to integers
oldPts = np.around(oldPts).astype(int)
newPts = newPts.astype(int)

# put the oldPts into 2d array
H, xedg,yedg= np.histogram2d(oldPts[:,0],oldPts[:,1],
                         bins = [xMax,yMax], 
                         range = [[0, xMax], [0, yMax]])
finalNewList = []
N = 5
for pt in newPts:

    if not H[max(0,pt[0]-N):min(xMax,pt[0]+N),
         max(0,pt[1]- N):min(yMax,pt[1]+N)].any():
        finalNewList.append(pt)

finalNew = np.array(finalNewList)  

1 Ответ

0 голосов
/ 11 июня 2019

Правильный способ сделать это - использовать линейную алгебру для вычисления расстояния между каждой парой 2-длинных векторов, а затем принимать только новые точки, которые «достаточно отличаются» от каждой старой точки: использование scipy.spatial.distance.cdist:

import numpy as np
oldPts = np.random.randn(1000,2)
newPts = np.random.randn(2000,2)

from scipy.spatial.distance import cdist
dist = cdist(oldPts, newPts)
print(dist.shape) # (1000, 2000)

okIndex = np.max(dist, axis=0) > 5
print(np.sum(okIndex)) # prints 1503 for me

finalNew = newPts[okIndex,:]
print(finalNew.shape) # (1503, 2)

Выше я использую евклидово расстояние 5 в качестве порога для «слишком близкого»: любая точка в newPts, которая дальше 5 от всех точек в oldPts, принимается в finalPts. Вам придется взглянуть на диапазон значений в dist, чтобы найти хороший порог, но ваша гистограмма может помочь вам выбрать лучший.

(Один хороший способ визуализации dist - использовать matplotlib.pyplot.imshow(dist).)

Это более точная версия того, что вы делали с гистограммой. Фактически, вы должны иметь возможность получить тот же самый ответ, что и гистограмма, передав metric='minkowski', p=1 аргументы ключевых слов в cdist, предполагая, что ширина бина вашей гистограммы одинакова в обоих измерениях, и снова используя 5 в качестве порога.

(PS. Если вас интересует другая полезная функция в scipy.spatial.distance, проверьте мой ответ, который использует pdist для поиска уникальных строк / столбцов в массиве .)

...