X और y निर्देशांक के संख्यात्मक सरणियों में निकटतम बिंदु का सूचकांक खोजना


83

मेरे पास दो 2 डी अंक वाली सरणियाँ हैं: x_array में x- दिशा में स्थितीय जानकारी है, y_array में y- दिशा में स्थितियाँ हैं।

मेरे पास तब x, y बिंदुओं की एक लंबी सूची है।

सूची में प्रत्येक बिंदु के लिए, मुझे उस स्थान के सरणी सूचकांक (सरणियों में निर्दिष्ट) को खोजने की आवश्यकता है जो उस बिंदु के सबसे करीब है।

मैंने इस प्रश्न के आधार पर कुछ कोड तैयार किए हैं, जो काम करता है: निकटतम मान का पता लगाएं

अर्थात

import time
import numpy

def find_index_of_nearest_xy(y_array, x_array, y_point, x_point):
    distance = (y_array-y_point)**2 + (x_array-x_point)**2
    idy,idx = numpy.where(distance==distance.min())
    return idy[0],idx[0]

def do_all(y_array, x_array, points):
    store = []
    for i in xrange(points.shape[1]):
        store.append(find_index_of_nearest_xy(y_array,x_array,points[0,i],points[1,i]))
    return store


# Create some dummy data
y_array = numpy.random.random(10000).reshape(100,100)
x_array = numpy.random.random(10000).reshape(100,100)

points = numpy.random.random(10000).reshape(2,5000)

# Time how long it takes to run
start = time.time()
results = do_all(y_array, x_array, points)
end = time.time()
print 'Completed in: ',end-start

मैं इसे बड़े डेटासेट पर कर रहा हूं और वास्तव में इसे थोड़ा गति देना चाहता हूं। क्या कोई इसका अनुकूलन कर सकता है?

धन्यवाद।


अद्यतन: @silvado और @justin (नीचे) द्वारा सुझावों का समाधान

# Shoe-horn existing data for entry into KDTree routines
combined_x_y_arrays = numpy.dstack([y_array.ravel(),x_array.ravel()])[0]
points_list = list(points.transpose())


def do_kdtree(combined_x_y_arrays,points):
    mytree = scipy.spatial.cKDTree(combined_x_y_arrays)
    dist, indexes = mytree.query(points)
    return indexes

start = time.time()
results2 = do_kdtree(combined_x_y_arrays,points_list)
end = time.time()
print 'Completed in: ',end-start

ऊपर दिए गए इस कोड ने मेरे कोड को (100x100 मैट्रिसेस में 5000 अंकों की खोज) 100 गुना बढ़ा दिया। दिलचस्प बात यह है का उपयोग कर scipy.spatial.KDTree (के बजाय scipy.spatial.cKDTree ) मेरी भोली समाधान करने के लिए तुलनीय समय दिया था, तो यह cKDTree संस्करण का उपयोग कर निश्चित रूप से लायक है ...


1
बस एक अनुमान है लेकिन शायद एक kd पेड़ मदद करेगा। मुझे नहीं पता कि पायथन का कार्यान्वयन है या नहीं।
जस्टिन

कोई सूची बनाने और 'अंक' को स्थानांतरित करने की आवश्यकता नहीं है। इसके बजाय एक सरणी का उपयोग करें और अनुक्रमित उठाएं।
थियो सिमियर

जवाबों:


48

scipy.spatialएक केडी वृक्ष कार्यान्वयन भी है scipy.spatial.KDTree:।

दृष्टिकोण आम तौर पर एक kd पेड़ बनाने के लिए पहले बिंदु डेटा का उपयोग करना है। उस की कम्प्यूटेशनल जटिलता एन लॉग एन के आदेश पर है, जहां एन डेटा बिंदुओं की संख्या है। रेंज क्वेरीज़ और निकटतम पड़ोसी खोजों को लॉग एन जटिलता के साथ किया जा सकता है। यह सभी बिंदुओं (जटिलता एन) के माध्यम से साइकिल चलाने की तुलना में बहुत अधिक कुशल है।

इस प्रकार, यदि आपने बार-बार या निकटतम पड़ोसी प्रश्नों को दोहराया है, तो एक kd पेड़ अत्यधिक अनुशंसित है।


1
यह बहुत ही आशाजनक लग रहा है। मैं इसके बारे में पढ़ना शुरू करूंगा और देखूंगा कि क्या मुझे कुछ काम मिल सकता है ...
पीट डब्ल्यू

1
मैं अभी भी अपने कोड का परीक्षण कर रहा हूं, लेकिन शुरुआती संकेत हैं कि scipy.spatial.cKDTree का उपयोग करना मेरे भोले दृष्टिकोण की तुलना में लगभग 100 गुना तेज है। जब मुझे कल अधिक समय मिलेगा तो मैं अपना अंतिम कोड पोस्ट कर दूंगा और सबसे अधिक संभावना है कि इस उत्तर को स्वीकार करूंगा (जब तक कि कोई तेज तरीका पहले नहीं आता है)। आपकी सहायता के लिए धन्यवाद।
पीट डब्ल्यू

ठीक है, scipy.spatial.cKDTree का उपयोग करने के लिए जाने का रास्ता लगता है। मेरे परीक्षण डेटा के साथ परीक्षण से पता चला है कि मानक scipy.spatial.KDTree मेरे भोले समाधान पर बहुत अधिक / कोई सुधार नहीं देता है।
पीट डब्ल्यू

75

यहाँ एक scipy.spatial.KDTreeउदाहरण है

In [1]: from scipy import spatial

In [2]: import numpy as np

In [3]: A = np.random.random((10,2))*100

In [4]: A
Out[4]:
array([[ 68.83402637,  38.07632221],
       [ 76.84704074,  24.9395109 ],
       [ 16.26715795,  98.52763827],
       [ 70.99411985,  67.31740151],
       [ 71.72452181,  24.13516764],
       [ 17.22707611,  20.65425362],
       [ 43.85122458,  21.50624882],
       [ 76.71987125,  44.95031274],
       [ 63.77341073,  78.87417774],
       [  8.45828909,  30.18426696]])

In [5]: pt = [6, 30]  # <-- the point to find

In [6]: A[spatial.KDTree(A).query(pt)[1]] # <-- the nearest point 
Out[6]: array([  8.45828909,  30.18426696])

#how it works!
In [7]: distance,index = spatial.KDTree(A).query(pt)

In [8]: distance # <-- The distances to the nearest neighbors
Out[8]: 2.4651855048258393

In [9]: index # <-- The locations of the neighbors
Out[9]: 9

#then 
In [10]: A[index]
Out[10]: array([  8.45828909,  30.18426696])

5
कार्यशील (सरल) उदाहरण के साथ पूर्ण उत्तर के लिए धन्यवाद, इसकी सराहना करते हैं!
जॉन्डोडो

@lostCrotchet मुझे लगता है कि .. मैं भी डेटा की एक जोड़ी से अधिक के साथ इसका इस्तेमाल किया है। उदा। (x, y, z, i)
efirvida

5

यदि आप अपने डेटा को सही प्रारूप में मालिश कर सकते हैं, तो जाने का एक तेज़ तरीका निम्नलिखित तरीकों का उपयोग करना है scipy.spatial.distance:

http://docs.scipy.org/doc/scipy/reference/spatial.distance.html

विशेष रूप से pdistऔर cdistजोड़ीदार दूरी की गणना करने के लिए तेज़ तरीके प्रदान करते हैं।


मैं उस मालिश को भी कहता हूं, यह बहुत वर्णन करता है कि हम डेटा के साथ क्या करते हैं। : डी
लोरिनि नित्राई

1
Scipy.spatil.distance महान उपकरण है लेकिन इस बात से अवगत रहें कि यदि आपके पास cKdtree की गणना करने के लिए बहुत अधिक दूरी है तो cdist की तुलना में बहुत तेज है।
लॉसब्लेटिका

1
अगर मुझे गलत समझा नहीं जाता है, तो cdist () या अन्य Numpy विधि का उपयोग करके इस उत्तर में दिखाया गया है codereview.stackexchange.com/a/134918/156228
एलेक्स एफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.