2013-08-30 6 views
5

के खिलाफ बेवकूफ कुशल एक है मेरे पास 3 डी निर्देशांक का एक सरणी 3xN है और मैं कुशलता से सभी प्रविष्टियों के दूरी मैट्रिक्स की गणना करना चाहता हूं। क्या नेस्टेड लूप के बजाए कोई कुशल पाश रणनीति लागू हो सकती है?सभी

वर्तमान स्यूडोकोड कार्यान्वयन:

for i,coord in enumerate(coords): 
    for j,coords2 in enumerate(coords): 
     if i != j: 
      dist[i,j] = numpy.norm(coord - coord2) 
+3

['scipy.spatial.distance.pdist'] का उपयोग करें (http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.pdist.html#scipy.spatial.distance। pdist)। – BrenBarn

उत्तर

5

वास्तव में अपने परिणामों को पुन: पेश करने के लिए:

>>> import scipy.spatial as sp 
>>> import numpy as np 
>>> a=np.random.rand(5,3) #Note this is the transpose of your array. 
>>> a 
array([[ 0.83921304, 0.72659404, 0.50434178], #0 
     [ 0.99883826, 0.91739731, 0.9435401 ], #1 
     [ 0.94327962, 0.57665875, 0.85853404], #2 
     [ 0.30053567, 0.44458829, 0.35677649], #3 
     [ 0.01345765, 0.49247883, 0.11496977]]) #4 
>>> sp.distance.cdist(a,a) 
array([[ 0.  , 0.50475862, 0.39845025, 0.62568048, 0.94249268], 
     [ 0.50475862, 0.  , 0.35554966, 1.02735895, 1.35575051], 
     [ 0.39845025, 0.35554966, 0.  , 0.82602847, 1.1935422 ], 
     [ 0.62568048, 1.02735895, 0.82602847, 0.  , 0.3783884 ], 
     [ 0.94249268, 1.35575051, 1.1935422 , 0.3783884 , 0.  ]]) 

डुप्लिकेट गणना के बिना और अधिक कुशलता से यह ऐसा करने के लिए और केवल अद्वितीय जोड़े गणना:

>>> sp.distance.pdist(a) 
array([ 0.50475862, 0.39845025, 0.62568048, 0.94249268, 0.35554966, 
     1.02735895, 1.35575051, 0.82602847, 1.1935422 , 0.3783884 ]) 
#pairs: [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), 
#   (2, 4), (3, 4)] 

नोट दो सरणी के बीच संबंध। cdist सरणी द्वारा reproduced किया जा सकता है:

>>> out=np.zeros((a.shape[0],a.shape[0])) 
>>> dists=sp.distance.pdist(a) 
>>> out[np.triu_indices(a.shape[0],1)]=dists 
>>> out+=out.T 

>>> out 
array([[ 0.  , 0.50475862, 0.39845025, 0.62568048, 0.94249268], 
     [ 0.50475862, 0.  , 0.35554966, 1.02735895, 1.35575051], 
     [ 0.39845025, 0.35554966, 0.  , 0.82602847, 1.1935422 ], 
     [ 0.62568048, 1.02735895, 0.82602847, 0.  , 0.3783884 ], 
     [ 0.94249268, 1.35575051, 1.1935422 , 0.3783884 , 0.  ]]) 

कुछ कुछ आश्चर्य की बात timings-

स्थापना:

def pdist_toarray(a): 
    out=np.zeros((a.shape[0],a.shape[0])) 
    dists=sp.distance.pdist(a) 

    out[np.triu_indices(a.shape[0],1)]=dists 
    return out+out.T 

def looping(a): 
    out=np.zeros((a.shape[0],a.shape[0])) 
    for i in xrange(a.shape[0]): 
     for j in xrange(a.shape[0]): 
      out[i,j]=np.linalg.norm(a[i]-a[j]) 
    return out 

समय:

arr=np.random.rand(1000,3) 

%timeit sp.distance.pdist(arr) 
100 loops, best of 3: 4.26 ms per loop 

%timeit sp.distance.cdist(arr,arr) 
100 loops, best of 3: 9.31 ms per loop 

%timeit pdist_toarray(arr) 
10 loops, best of 3: 66.2 ms per loop 

%timeit looping(arr) 
1 loops, best of 3: 16.7 s per loop 

तो अगर आप चाहते हैं वर्ग ए यदि आप चाहते हैं कि जोड़े pdist का उपयोग करें तो आपको cdist का उपयोग करना चाहिए। लूपिंग 0 तत्वों के साथ ~ 4000x धीमी है और 1000 तत्वों के साथ ~ 70x धीमी है और cdist की तुलना में 10 तत्वों के साथ सरणी है।

+0

Scipy वेक्टर और मैट्रिक्स के बीच कनवर्ट करने के लिए ['squareform'] (https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.distance.squareform.html) फ़ंक्शन प्रदान करता है दूरी सरणी के संस्करण ("संघनित" और "अनावश्यक" रूप) – Praveen