2013-06-07 12 views
28

मैं किसी खास कुंजी के अनुसार एक numpy.array के प्रत्येक तत्व का अनुवाद करने में कोशिश कर रहा हूँ के अनुसार:numpy सरणी में प्रत्येक तत्व अनुवाद कुंजी

उदाहरण के लिए:

:

a = np.array([[1,2,3], 
       [3,2,4]]) 

my_dict = {1:23, 2:34, 3:36, 4:45} 

मैं प्राप्त करना चाहते हैं

array([[ 23., 34., 36.], 
     [ 36., 34., 45.]]) 

मैं कैसे एक पाश के साथ यह करने के लिए देख सकते हैं:

def loop_translate(a, my_dict): 
    new_a = np.empty(a.shape) 
    for i,row in enumerate(a): 
     new_a[i,:] = map(my_dict.get, row) 
    return new_a 

क्या कोई और अधिक कुशल और/या शुद्ध numpy तरीका है?

संपादित करें:

मैं इसे समय समाप्त हो गया है, और np.vectorize विधि डीएसएम द्वारा प्रस्तावित काफी तेज बड़े विन्यास के लिए है:

In [13]: def loop_translate(a, my_dict): 
    ....:  new_a = np.empty(a.shape) 
    ....:  for i,row in enumerate(a): 
    ....:   new_a[i,:] = map(my_dict.get, row) 
    ....:  return new_a 
    ....: 

In [14]: def vec_translate(a, my_dict):  
    ....:  return np.vectorize(my_dict.__getitem__)(a) 
    ....: 

In [15]: a = np.random.randint(1,5, (4,5)) 

In [16]: a 
Out[16]: 
array([[2, 4, 3, 1, 1], 
     [2, 4, 3, 2, 4], 
     [4, 2, 1, 3, 1], 
     [2, 4, 3, 4, 1]]) 

In [17]: %timeit loop_translate(a, my_dict) 
10000 loops, best of 3: 77.9 us per loop 

In [18]: %timeit vec_translate(a, my_dict) 
10000 loops, best of 3: 70.5 us per loop 

In [19]: a = np.random.randint(1, 5, (500,500)) 

In [20]: %timeit loop_translate(a, my_dict) 
1 loops, best of 3: 298 ms per loop 

In [21]: %timeit vec_translate(a, my_dict) 
10 loops, best of 3: 37.6 ms per loop 

In [22]: %timeit loop_translate(a, my_dict) 
+2

संबंधित प्रश्न: http://stackoverflow.com/questions/3403973/fast-replacement-of-values-in-a-numpy-array –

उत्तर

33

मैं के बारे में कुशल नहीं पता है, लेकिन आप पर np.vectorize इस्तेमाल कर सकते हैं .get शब्दकोशों की विधि:

>>> a = np.array([[1,2,3], 
       [3,2,4]]) 
>>> my_dict = {1:23, 2:34, 3:36, 4:45} 
>>> np.vectorize(my_dict.get)(a) 
array([[23, 34, 36], 
     [36, 34, 45]]) 
+4

+1 अगर ओपी जानता है कि हर कुंजी 'my_dict' में रखी जाएगी जैसा कि 'ए' में है, फिर 'my_dict .__ getitem__' बेहतर विकल्प होगा – jamylak

+0

@ अक्कवाल: यह अजीब बात है। हालांकि, जांच करने के लिए मेरे पास 1.6.2 के आसपास नहीं है। – DSM

+0

जब मैं 'my_dict.get' का उपयोग कर रहा हूं, मुझे ValueError मिल रहा है, लेकिन जब मैं' my_dict .__ getitem__' का उपयोग कर रहा हूं तो मुझे उस समस्या का सामना नहीं है। मैं इस नमूना डेटा का उपयोग कर numpy 1.6.2 – Akavall

5

मुझे लगता है कि यह मेरे लिए बेहतर होगा "एक बार में" सभी पंक्तियों और स्तंभों में शब्दकोश से अधिक Terate, और सेट मान:

>>> a = np.array([[1,2,3],[3,2,1]]) 
>>> a 
array([[1, 2, 3], 
     [3, 2, 1]]) 
>>> d = {1 : 11, 2 : 22, 3 : 33} 
>>> for k,v in d.iteritems(): 
...  a[a == k] = v 
... 
>>> a 
array([[11, 22, 33], 
     [33, 22, 11]]) 

संपादित करें:

हालांकि यह रूप में सेक्सी DSM's (really good) answer रूप numpy.vectorize सभी के अपने परीक्षण का उपयोग कर, नहीं हो सकता है प्रस्तावित तरीकों पता चलता है कि इस दृष्टिकोण (@ jamylak के सुझाव का प्रयोग करके) वास्तव में एक सा तेजी से होता है:

from __future__ import division 
import numpy as np 
a = np.random.randint(1, 5, (500,500)) 
d = {1 : 11, 2 : 22, 3 : 33, 4 : 44} 

def unique_translate(a,d): 
    u,inv = np.unique(a,return_inverse = True) 
    return np.array([d[x] for x in u])[inv].reshape(a.shape) 

def vec_translate(a, d):  
    return np.vectorize(d.__getitem__)(a) 

def loop_translate(a,d): 
    n = np.ndarray(a.shape) 
    for k in d: 
     n[a == k] = d[k] 
    return n 

def orig_translate(a, d): 
    new_a = np.empty(a.shape) 
    for i,row in enumerate(a): 
     new_a[i,:] = map(d.get, row) 
    return new_a 


if __name__ == '__main__': 
    import timeit 
    n_exec = 100 
    print 'orig' 
    print timeit.timeit("orig_translate(a,d)", 
         setup="from __main__ import np,a,d,orig_translate", 
         number = n_exec)/n_exec 
    print 'unique' 
    print timeit.timeit("unique_translate(a,d)", 
         setup="from __main__ import np,a,d,unique_translate", 
         number = n_exec)/n_exec 
    print 'vec' 
    print timeit.timeit("vec_translate(a,d)", 
         setup="from __main__ import np,a,d,vec_translate", 
         number = n_exec)/n_exec 
    print 'loop' 
    print timeit.timeit("loop_translate(a,d)", 
         setup="from __main__ import np,a,d,loop_translate", 
         number = n_exec)/n_exec 

आउटपुट:

+०१२३५१६४१०
orig 
0.222067718506 
unique 
0.0472617006302 
vec 
0.0357889199257 
loop 
0.0285375618935 
+0

गति को ध्यान में रखना एक मुद्दा हो सकता है, 'के लिए डी' के रूप में पुनरावृत्ति करना जितना तेज़ हो सकेगा – jamylak

+1

मुझे लगता है कि वेक्टरिंग मेरी स्थिति के लिए तेज़ है, जहां '' आकार '(50, 50, 50) ' , 'd' में 5000 कुंजी हैं, और डेटा' numpy.uint32' है। और यह बहुत करीब नहीं है ... ~ 0.1 सेकंड बनाम ~ 1.4 सेकंड। सरणी flattening मदद नहीं करता है। :/ – grisaitis

5

यहाँ, एक और तरीका है numpy.unique का उपयोग कर:

>>> a = np.array([[1,2,3],[3,2,1]]) 
>>> a 
array([[1, 2, 3], 
     [3, 2, 1]]) 
>>> d = {1 : 11, 2 : 22, 3 : 33} 
>>> u,inv = np.unique(a,return_inverse = True) 
>>> np.array([d[x] for x in u])[inv].reshape(a.shape) 
array([[11, 22, 33], 
     [33, 22, 11]]) 
+0

'vectorize (dict.get)' का उपयोग करने के लिए यह गति-वार की तुलना कैसे करता है? – grisaitis

+0

परिशिष्ट - मैंने इसे सबसे तेज़ पाया (वेक्टरिंग dictionary.get की तुलना में और चाबियों के माध्यम से पुनरावृत्ति)! ymmv ... – grisaitis

+1

मैं एक मामूली संशोधन करूँगा, जो 'd [x]' 'd.get (x, default_value) 'के साथ प्रतिस्थापित करना है, जहां' default_value' जो भी आप चाहते हैं हो सकता है। मेरे उपयोग के मामले में, मैं केवल कुछ मूल्यों को प्रतिस्थापित कर रहा था, और अन्य जिन्हें मैं अकेला छोड़ना चाहता था, इसलिए मैंने 'd.get (x, x)' किया। – grisaitis

0

तुम सच में उपयोग शब्दकोश में है प्रतिस्थापन तालिका के रूप में नहीं करते हैं, सरल समाधान (आपके उदाहरण के लिए) होगा:

a = numpy.array([your array]) 
my_dict = numpy.array([0, 23, 34, 36, 45])  # your dictionary as array 

def Sub (myarr, table) : 
    return table[myarr] 

values = Sub(a, my_dict) 

यह केवल तभी काम करेगा जब d के इंडेक्स आपके a के सभी संभावित मूल्यों को कवर करते हैं, दूसरे शब्दों में, केवल a के लिए उपयोग के साथ एड पूर्णांक।

2

numpy_indexed पैकेज (अस्वीकरण: मैं उसके लेखक हूँ) इस प्रकार की समस्या के लिए एक सुंदर और कुशल vectorized समाधान प्रदान करता है:

import numpy_indexed as npi 
remapped_a = npi.remap(a, list(my_dict.keys()), list(my_dict.values())) 

पद्धति लागू दृष्टिकोण जॉन विनयार्ड ने उल्लेख के समान है, लेकिन फिर भी ज़्यादा सामान्य। उदाहरण के लिए, सरणी के आइटम को चींटियों की आवश्यकता नहीं होती है, लेकिन किसी भी प्रकार, यहां तक ​​कि एनडी-सबरेज़ भी हो सकती है।

यदि आप वैकल्पिक 'गायब' kwarg को 'raise' (डिफ़ॉल्ट 'अनदेखा') पर सेट करते हैं, तो प्रदर्शन थोड़ा बेहतर होगा, और यदि आप 'ए' के ​​सभी तत्व कुंजी में मौजूद नहीं हैं तो आपको एक KeyError मिल जाएगा ।

1

मान लीजिए कि आपकी डंक कुंजियां सकारात्मक अंतराल हैं, बिना विशाल अंतराल (0 से एन तक की सीमा के समान), आप अपने अनुवाद dict को एक सरणी में परिवर्तित करना बेहतर कर सकते हैं जैसे कि my_array[i] = my_dict[i], और अनुवाद करने के लिए numpy अनुक्रमण का उपयोग करना ।

इस दृष्टिकोण का उपयोग कर एक कोड है:

यादृच्छिक सरणियों के साथ
def direct_translate(a, d): 
    src, values = d.keys(), d.values() 
    d_array = np.arange(a.max() + 1) 
    d_array[src] = values 
    return d_array[a] 

परीक्षण:

N = 10000 
shape = (5000, 5000) 
a = np.random.randint(N, size=shape) 
my_dict = dict(zip(np.arange(N), np.random.randint(N, size=N))) 

इन आकारों मैं इस दृष्टिकोण के लिए चारों ओर 140 ms पाने के लिए। Np.get vectorization 5.8 s और unique_translate के आसपास 8 s लेता है।

संभव सामान्यीकरण:

  • आप अनुवाद करना ऋणात्मक मानों है, तो आप मान a में और शब्दकोश की कुंजी में एक निरंतर द्वारा बदलाव कर सकता है उन्हें वापस धनात्मक पूर्णांक को मैप करने के:

def direct_translate(a, d): # handles negative source keys 
    min_a = a.min() 
    src, values = np.array(d.keys()) - min_a, d.values() 
    d_array = np.arange(a.max() - min_a + 1) 
    d_array[src] = values 
    return d_array[a - min_a] 
  • यदि स्रोत कुंजी के पास विशाल अंतर हैं, तो प्रारंभिक सरणी निर्माण स्मृति को बर्बाद कर देगा। मैं उस समारोह को तेज करने के लिए साइथन का सहारा लेगा।
संबंधित मुद्दे