2015-06-27 13 views
8

में प्रत्येक तत्व के लिए 2 डी इंडेक्स (संभावित डुप्लिकेट के साथ) के यादृच्छिक सरणी में प्रत्येक तत्व के लिए, मैं 2 डी शून्य सरणी में संबंधित ग्रिड में "+ = 1" करना चाहता हूं। हालांकि, मुझे नहीं पता कि गणना कैसे अनुकूलित करें। मानक, जैसा कि यहाँ दिखाया, पाश के लिए उपयोग करनाNumPy arrays

def interadd(): 
    U = 100 
    input = np.random.random(size=(5000,2)) * U 
    idx = np.floor(input).astype(np.int) 

    grids = np.zeros((U,U))  
    for i in range(len(input)): 
     grids[idx[i,0],idx[i,1]] += 1 
    return grids 

क्रम काफी महत्वपूर्ण हो सकता है:

>> timeit(interadd, number=5000) 
43.69953393936157 

इस सतत प्रक्रिया vectorize के लिए एक रास्ता है?

उत्तर

8

आप np.add.at है, जो सही ढंग से डुप्लिकेट सूचकांक के मामले हैंडल का उपयोग करके एक छोटे से इसे गति कर सकते हैं:

def interadd(U, idx): 
    grids = np.zeros((U,U))  
    for i in range(len(idx)): 
     grids[idx[i,0],idx[i,1]] += 1 
    return grids 

def interadd2(U, idx): 
    grids = np.zeros((U,U)) 
    np.add.at(grids, idx.T.tolist(), 1) 
    return grids 

def interadd3(U, idx): 
    # YXD suggestion 
    grids = np.zeros((U,U)) 
    np.add.at(grids, (idx[:,0], idx[:,1]), 1) 
    return grids 

जो

>>> U = 100 
>>> idx = np.floor(np.random.random(size=(5000,2))*U).astype(np.int) 
>>> (interadd(U, idx) == interadd2(U, idx)).all() 
True 
>>> %timeit interadd(U, idx) 
100 loops, best of 3: 8.48 ms per loop 
>>> %timeit interadd2(U, idx) 
100 loops, best of 3: 2.62 ms per loop 

देता है और YXD के सुझाव:

>>> (interadd(U, idx) == interadd3(U, idx)).all() 
True 
>>> %timeit interadd3(U, idx) 
1000 loops, best of 3: 1.09 ms per loop 
+4

लगभग एक ही thing.You 'IDX बदल सकते हैं टाइपिंग था। टी। टोलिस्ट() 'से' (idx [:, 0], idx [:, 1]) ', अभी भी तेज़ होना चाहिए। – YXD

+1

(टाइपो अभी ऊपर टिप्पणी में सही किया गया है) – YXD

5

आप R,C सूचकांक idx से रैखिक सूचकांक में कनवर्ट कर सकते हैं, फिर अनन्य को अपने गिनती के साथ ढूंढें और आखिरकार आउटपुट grids को अंतिम आउटपुट के रूप में स्टोर करें।

# Calculate linear indices corressponding to idx 
lin_idx = idx[:,0]*U + idx[:,1] 

# Get unique linear indices and their counts 
unq_lin_idx,idx_counts = np.unique(lin_idx,return_counts=True) 

# Setup output array and store index counts in raveled/flattened version 
grids = np.zeros((U,U)) 
grids.ravel()[unq_lin_idx] = idx_counts 

रनटाइम परीक्षण - -

यहाँ (@DSM's approaches सहित) और कहा कि समाधान में सूचीबद्ध के रूप में ही परिभाषाओं का उपयोग सभी दृष्टिकोणों को कवर क्रम परीक्षण कर रहे हैं -

In [63]: U = 100 
    ...: idx = np.floor(np.random.random(size=(5000,2))*U).astype(np.int) 
    ...: 

In [64]: %timeit interadd(U, idx) 
100 loops, best of 3: 7.57 ms per loop 

In [65]: %timeit interadd2(U, idx) 
100 loops, best of 3: 2.59 ms per loop 

In [66]: %timeit interadd3(U, idx) 
1000 loops, best of 3: 1.24 ms per loop 

In [67]: def unique_counts(U, idx): 
    ...:  lin_idx = idx[:,0]*U + idx[:,1] 
    ...:  unq_lin_idx,idx_counts = np.unique(lin_idx,return_counts=True) 
    ...:  grids = np.zeros((U,U)) 
    ...:  grids.ravel()[unq_lin_idx] = idx_counts 
    ...:  return grids 
    ...: 

In [68]: %timeit unique_counts(U, idx) 
1000 loops, best of 3: 595 µs per loop 
यहाँ कार्यान्वयन एक ही प्राप्त करने के लिए है

रनटाइम सुझाव देते हैं कि प्रस्तावित np.unique आधारित दृष्टिकोण दूसरे सबसे तेज़ दृष्टिकोण से 50% से अधिक तेज है।

+0

'np.unique' हुड के नीचे सॉर्टिंग का उपयोग करता है, इसलिए' np.add.at' की तुलना में खराब समय जटिलता है, लेकिन दूसरी तरफ आपके दृष्टिकोण में तेज़ मेमोरी एक्सेस पैटर्न है 'ग्रिड 'सरणी। –

+0

@moarningsun हाँ मुझे लगता है कि यह हुड के तहत 'सॉर्टिंग' और 'भेदभाव' का उपयोग करता है। यह समझ में आता है कि मैं उस तेज रनटाइम पर अनुमान लगाता हूं। 'Add.at' के नीचे क्या हो रहा है यह जानने के लिए दिलचस्प होगा। – Divakar

+0

इसने मुझे एक दिलचस्प दृष्टिकोण के बारे में सोचा: 'grids = np.bincount (lin_idx, minlength = U ** 2) .reshape (U, U)' –

6

दिवाकर का जवाब मुझे नेतृत्व निम्नलिखित है, जो अभी तक सबसे तेजी से विधि के लिए लग रहा है की कोशिश करने के लिए:

lin_idx = idx[:,0]*U + idx[:,1] 
grids = np.bincount(lin_idx, minlength=U**2).reshape(U, U) 

समय:

In [184]: U = 100 
    ...: input = np.random.random(size=(5000,2)) * U 
    ...: idx = np.floor(input).astype(np.int) 

In [185]: %timeit interadd3(U, idx) # By DSM/XYD 
1000 loops, best of 3: 1.68 ms per loop 

In [186]: %timeit unique_counts(U, idx) # By Divakar 
1000 loops, best of 3: 676 µs per loop 

In [187]: %%timeit 
    ...: lin_idx = idx[:,0]*U + idx[:,1] 
    ...: grids = np.bincount(lin_idx, minlength=U*U).reshape(U, U) 
    ...: 
10000 loops, best of 3: 97.5 µs per loop 
+0

भारी सुधार ऐसा लगता है! – Divakar

संबंधित मुद्दे