2013-05-16 16 views
33

के लिए हैश के लिए सबसे अधिक कुशल संपत्ति कैशिंग उद्देश्यों के लिए dict में मुझे numpyarray स्टोर करने में सक्षम होना चाहिए। हैश गति महत्वपूर्ण है।numpy array

array इंडस्ट्रीज का प्रतिनिधित्व करता है, इसलिए ऑब्जेक्ट की वास्तविक पहचान महत्वपूर्ण नहीं है, मान है। उत्परिवर्तन चिंता का विषय नहीं है, क्योंकि मुझे केवल वर्तमान मूल्य में दिलचस्पी है।

dict में इसे संग्रहीत करने के लिए मुझे क्या हैश करना चाहिए?

मेरा वर्तमान दृष्टिकोण str(arr.data) का उपयोग करना है, जो मेरे परीक्षण में md5 से तेज़ है।

In [121]: %timeit hash(str(y)) 
10000 loops, best of 3: 68.7 us per loop 

In [122]: %timeit hash(y.tostring()) 
1000000 loops, best of 3: 383 ns per loop 

In [123]: %timeit hash(str(y.data)) 
1000000 loops, best of 3: 543 ns per loop 

In [124]: %timeit y.flags.writeable = False ; hash(y.data) 
1000000 loops, best of 3: 1.15 us per loop 

In [125]: %timeit hash((b*y).sum()) 
100000 loops, best of 3: 8.12 us per loop 

ऐसा लगता है कि इस विशेष उपयोग के मामले के लिए (indicies के छोटे सरणियों), arr.tostring प्रदान करता है:


मैं जवाब से कुछ उदाहरण शामिल किया गया है रिश्तेदार समय की एक विचार प्राप्त करने के लिए सबसे अच्छा प्रदर्शन।

जबकि केवल पढ़ने-योग्य बफर हैशिंग अपने आप पर तेज है, लिखने योग्य ध्वज को स्थापित करने के ऊपरी हिस्से में यह वास्तव में धीमा हो जाता है।

+2

'arr.tostring() 'वही करता है और अधिक सौंदर्यपूर्ण रूप से प्रसन्न होता है। यदि आपके पास वास्तव में बड़े सरणी हैं तो आप सरणी के केवल एक छोटे हिस्से को स्ट्रिंग करने का प्रयास कर सकते हैं। – root

+0

'tostring' छोटे सरणी के लिए तीव्रता के क्रम भी प्रतीत होता है (हालांकि 400 10000 तत्वों की सरणी के लिए धीमा)। –

+4

... जो वास्तव में काफी स्पष्ट है, क्योंकि 'str' केवल सरणी के सिर और पूंछ को स्वरूपित करता है। –

उत्तर

26

आप बस, अंतर्निहित बफर हैश सकते यदि आप इसे केवल पढ़ने के लिए करते हैं:

>>> a = random.randint(10, 100, 100000) 
>>> a.flags.writeable = False 
>>> %timeit hash(a.data) 
100 loops, best of 3: 2.01 ms per loop 
>>> %timeit hash(a.tostring()) 
100 loops, best of 3: 2.28 ms per loop 

बहुत बड़ी सरणियों के लिए, hash(str(a)) एक बहुत तेजी से होता है, लेकिन फिर यह केवल में सरणी के एक छोटे से भाग लेता है लेखा।

>>> %timeit hash(str(a)) 
10000 loops, best of 3: 55.5 us per loop 
>>> str(a) 
'[63 30 33 ..., 96 25 60]' 
+0

धन्यवाद। मैं अभी के लिए 'tostring' का उपयोग करने जा रहा हूं, लेकिन मैं अपने इनपुट तर्कों को थोड़ा बदलना जांच सकता हूं ताकि मैं केवल पढ़ने के लिए बफर का उपयोग कर सकूं, जिससे हैश तेजी से हो सके। – sapi

+9

पायथन 3.4 में मैंने पाया कि मुझे 'हैश (a.data.tobytes())' ' – ariddell

+0

का उपयोग करना पड़ा था, इस तरह के देर से आने के लिए खेद है, लेकिन 'हैश (a.data.tobytes())' @iddell के रूप में उपयोग करना सुझाव दिया गया है कि मुझे 'a.flags.writeable = false' सेट करने की आवश्यकता नहीं है। ऐसा करने के लिए कोई कारण और ऐसा करने में कोई संभावित समस्या है? – SCB

2

आपके पास किस प्रकार का डेटा है?

  • सरणी आकार
  • आप सरणी

में एक सूचकांक कई बार अपने सरणी केवल आप एक आधार-रूपांतरण

(1, 0, 2) -> 1 * 3**0 + 0 * 3**1 + 2 * 3**2 = 10(base3) 
उपयोग कर सकते हैं सूचकांक के क्रमचय के होते हैं, तो वैसा

और

import numpy as num 

base_size = 3 
base = base_size ** num.arange(base_size) 
max_base = (base * num.arange(base_size)).sum() 

hashed_array = (base * array).sum() 
के माध्यम से हैश_की के रूप में '10' का उपयोग करें

अब आप मूल्यों तक पहुंचने के लिए एक तीर के बजाय एक सरणी (आकार = (base_size,)) का उपयोग कर सकते हैं।

+1

सूची समझ क्यों? यह NumPy में 'base_size ** np.arange (base_size)' के रूप में बहुत तेज़ किया जा सकता है। –

+0

दिलचस्प दृष्टिकोण, हालांकि छोटे सरणी के लिए धीमा। अगर मुझे कुछ भी बड़ा खेलना है तो मैं इसे ध्यान में रखूंगा :) – sapi

1

पार्टी के लिए देर से आ रहा है, लेकिन बड़े सरणियों के लिए, मैं इसे बेतरतीब ढंग से मैट्रिक्स subsample और उस नमूना हैश करने के लिए है करने के लिए एक सभ्य तरीका लगता है:

def subsample_hash(a): 
    rng = np.random.RandomState(89) 
    inds = rng.randint(low=0, high=a.size, size=1000) 
    b = a.flat[inds] 
    b.flags.writeable = False 
    return hash(b.data) 

मुझे लगता है कि इस से बेहतर है hash(str(a)) कर रहा है, क्योंकि उत्तरार्द्ध उन सरणी को भ्रमित कर सकता है जिनमें मध्य में अद्वितीय डेटा है लेकिन किनारों के चारों ओर शून्य है।

14

आप को Python binding के माध्यम से आजमा सकते हैं। बड़े सरणी के लिए यह hash(x.tostring()) से बहुत तेज है।

उदाहरण IPython सत्र:

>>> import xxhash 
>>> import numpy 
>>> x = numpy.random.rand(1024 * 1024 * 16) 
>>> h = xxhash.xxh64() 
>>> %timeit hash(x.tostring()) 
1 loops, best of 3: 208 ms per loop 
>>> %timeit h.update(x); h.intdigest(); h.reset() 
100 loops, best of 3: 10.2 ms per loop 

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

फिर भी, हैश टकराव हर समय होता है। और यदि आपको केवल डेटा-सरणी ऑब्जेक्ट्स के लिए __hash__ लागू करना है ताकि उन्हें पायथन शब्दकोश या सेट में कुंजियों के रूप में उपयोग किया जा सके, मुझे लगता है कि __hash__ की गति पर ध्यान केंद्रित करना बेहतर है और पायथन को हैश टकराव [1] को संभालने दें।

[1] आपको पाइथन प्रबंधन हैश टकराव का प्रबंधन करने के लिए __eq__ को ओवरराइड करने की आवश्यकता हो सकती है। numpy द्वारा किए गए बूलियन की एक सरणी की बजाय, आप बूलियन लौटने के लिए __eq__ चाहते हैं।

+0

मुझे लगता है कि गैर-क्रिप्टोग्राफिक हैंश भी 'सामान्य' डेटा के लिए टकराव को रोकने की कोशिश करते हैं, है ना? क्रिप्टो भाग यह है कि एक दुर्भावनापूर्ण हमलावर को टकराव खोजने की संभावना नहीं हो सकती है या हैश ऑब्जेक्ट के बारे में जानना चाहिए। तो इस जवाब की तरह, प्रदर्शन करते समय निश्चित रूप से sha1 या md5 का उपयोग न करें और सुरक्षा नहीं है। – Mark

+0

चौथी पंक्ति 'h = xxhash.xxh64()' –

+1

@Micahmith धन्यवाद होना चाहिए। फिक्स्ड। –