2012-04-19 10 views
8

मैं एक बड़े (1,000,000 x 3,000) बूलियन numpy सरणी में एक अनुक्रमित वजन राशि की गणना करना चाहता हूँ। बड़ी बुलियन सरणी को बार-बार बदलती है, लेकिन वजन क्वेरी समय पर आते हैं, और मुझे बड़ी बड़ी सरणी की प्रतिलिपि के बिना, छोटे वज़न सरणी को बड़े सरणी के आकार में विस्तारित करने के बिना उत्तर की आवश्यकता है।कुशलता से एक छोटी संख्यात्मक सरणी समृद्ध, एक विशाल संख्यात्मक सरणी में प्रसारित?

परिणाम 1,000,000 प्रविष्टियों के साथ एक सरणी होना चाहिए, प्रत्येक में उस पंक्ति के True मानों के अनुरूप वजन वाली सरणी प्रविष्टियों का योग होना चाहिए।

मैंने मास्क किए गए सरणी का उपयोग करने में देखा, लेकिन उन्हें वजन की सरणी मेरे बड़े बुलियन सरणी के आकार की आवश्यकता होती है।

नीचे दिया गया कोड सही परिणाम देता है, लेकिन मैं गुणात्मक चरण के दौरान की प्रतिलिपि नहीं ले सकता। गुणा भी आवश्यक नहीं है, क्योंकि मान सरणी बुलियन है, लेकिन कम से कम यह प्रसारण को ठीक से संभालती है।

मैं numpy के लिए नया हूँ, और इसे प्यार करता हूँ, लेकिन मैं इस विशेष समस्या के लिए इसे छोड़ने वाला हूं। मैंने पाइथन में लूप्स से कुछ भी रहने के लिए पर्याप्त संख्या में सीखा है।

मेरे अगले कदम सी में इस दिनचर्या लिखने के लिए किया जाएगा (जो है, मुझे बाइट्स की बजाय बिट्स का उपयोग करके स्मृति को बचाने दे द्वारा रास्ते से जोड़ा लाभ।)

आप numpy गुरुओं में से एक जब तक मुझे साइथन से बचा सकता है?

from numpy import array, multiply, sum 

# Construct an example values array, alternating True and False. 
# This represents four records of three attributes each: 
# array([[False, True, False], 
#   [ True, False, True], 
#   [False, True, False], 
#   [ True, False, True]], dtype=bool) 
values = array([(x % 2) for x in range(12)], dtype=bool).reshape((4,3)) 

# Construct example weights, one for each attribute: 
# array([1, 2, 3]) 
weights = array(range(1, 4)) 

# Create expensive NEW array with the weights for the True attributes. 
# Broadcast the weights array into the values array. 
# array([[0, 2, 0], 
#   [1, 0, 3], 
#   [0, 2, 0], 
#   [1, 0, 3]]) 
weighted = multiply(values, weights) 

# Add up the weights: 
# array([2, 4, 2, 4]) 
answers = sum(weighted, axis=1) 

print answers 

# Rejected masked_array solution is too expensive (and oddly inverts 
# the results): 
masked = numpy.ma.array([[1,2,3]] * 4, mask=values) 
+2

आपको जो चाहिए वह उदाहरण के साथ बढ़िया काम। – steveha

उत्तर

4

डॉट उत्पाद (या आंतरिक उत्पाद) वह है जो आप चाहते हैं। यह आपको आकार m×n और n की लंबाई का एक वैट्रिक लेने की अनुमति देता है और उन्हें m की वेक्टर प्रदान करने के साथ गुणा करता है, जहां प्रत्येक प्रविष्टि वजन के रूप में वेक्टर की प्रविष्टियों के साथ मैट्रिक्स की एक पंक्ति का भारित योग होता है।

नकली इसे array1.dot(array2) (या पुराने संस्करणों में numpy.dot(array1, array2)) के रूप में लागू करता है। उदा .:

from numpy import array 

values = array([(x % 2) for x in range(12)], dtype=bool).reshape((4,3)) 

weights = array(range(1, 4)) 

answers = values.dot(weights) 
print answers 
# output: [ 2 4 2 4 ] 

(आप चाहिए बेंचमार्क इस हालांकि, timeit module इस्तेमाल करते हैं।)

+0

प्रेषक ने अपने उत्तर के साथ एक त्वरित बेंचमार्क शामिल किया; यह अच्छा प्रदर्शन किया। – agf

+0

यह बहुत ही बढ़िया है, मुझे दस्तावेज़ों के माध्यम से घूमने से डॉट फ़ंक्शन को बिल्कुल समझ में नहीं आया।मैंने इसे समय दिया, और दुर्भाग्य से यह मेरे उच्च CPU ec2 उदाहरण पर भी काफी तेज़ नहीं है, लेकिन यह वही है जो मैंने पूछा था, और मुझे इसके बारे में जानकर खुशी हुई, धन्यवाद! –

1

क्या यह आपके लिए काम करेगा?

a = np.array([sum(row * weights) for row in values]) 

यह sum() का उपयोग करता है तुरंत, row * weights मानों का योग करने ताकि आप सभी मध्यवर्ती मूल्यों स्टोर करने के लिए स्मृति की जरूरत नहीं है। फिर सूची समझ सभी मूल्यों को एकत्र करती है।

आपने कहा कि आप "पायथन में लूप" से बचने के लिए कुछ भी कहना चाहते हैं। यह कम से कम एक पायथन लूप की बजाय पाइथन के सी गेट्स के साथ लूपिंग करता है, लेकिन यह न्यूमपी समाधान के रूप में तेज़ नहीं हो सकता है क्योंकि यह संकलित सी या फोरट्रान का उपयोग करता है।

+0

मैं इसे छोड़ दूंगा, लेकिन @ dbaupp ने इसे दबाया। एक शुद्ध NumPy समाधान इससे बेहतर होने जा रहा है। – steveha

+0

हां, शुद्ध numpy एक जीत है, लेकिन यह भी एक अच्छी तरह से संक्षिप्त समाधान है, धन्यवाद! –

0

मैं तुम्हें ऐसा ही कुछ के लिए numpy की जरूरत नहीं लगता। और 30000000 से 3000 एक विशाल सरणी है; यह आपकी रैम में फिट नहीं होगा, सबसे अधिक संभावना है।

False,True,False 
True,False,True 
False,True,False 
True,False,True 

मेरे कोड:

weight = range(1,4)  
dicto = {'True':1, 'False':0} 

with open ('my_data.txt') as fin: 

    a = sum(sum(dicto[ele]*w for ele,w in zip(line.strip().split(','),weight)) for line in fin) 

परिणाम:

>>> a 
12 

मान लीजिए कि आप डेटा एक पाठ फ़ाइल में मूल रूप से है दो:

मैं इसे इस तरह से करना होगा

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

मुझे लगता है कि मैंने पहली बार प्रश्न को थोड़ा गलत तरीके से गलत तरीके से पढ़ा, और सब कुछ एक साथ समझाया।

weight = range(1,4) 
dicto = {'True':1, 'False':0} 

with open ('my_data.txt') as fin: 

    a = [sum(dicto[ele]*w for ele,w in zip(line.strip().split(','),weight)) for line in fin] 

परिणाम::

>>> a 
[2, 4, 2, 4] 
+2

32-बिट फ्लोट मानों की 3000 सरणी द्वारा 1000000 डेटा के बारे में 11.2 जीबीबी तक काम करता है। यदि उसके सच्चे/झूठे मान एकल-बाइट मान हैं, तो यह केवल 2.8 जीबी डेटा है। 32 जीबी या अधिक रैम वाले 64-बिट कंप्यूटर हैं, इसलिए फ्लोट सरणी भी उनके कंप्यूटर के आधार पर फिट हो सकती है। लेकिन अगर वह इसकी मदद कर सकता है तो वह इसकी कोई प्रतियां नहीं बनाना चाहेंगे! – steveha

+0

ठीक है, मैं देखता हूं। धन्यवाद। मुझे पता है कि यह मेरी रैम में फिट नहीं होगा! आकार के मामले में बस यह समाधान होना चाहता था। – Akavall

+0

स्टीव सही है, वे एकल-बाइट (dtype = bool) मान हैं और उन्हें रैम में रखने के लिए संभव है। और मेरी प्रदर्शन आवश्यकताओं के साथ, मैं वास्तव में डिस्क को भी स्पर्श करने का जोखिम नहीं उठा सकता, यहां तक ​​कि स्वैप करने के लिए भी। लेकिन मैं मानता हूं कि कम रैम के साथ धीमे समय पैमाने पर एक ही चीज़ करने के लिए यह एक उपयोगी जोड़ है, धन्यवाद! –

3

यह संभावना है कि dbaupp के जवाब सही एक है यहाँ समाधान है कि सटीक समाधान है कि ओपी के बाद है देता है। लेकिन सिर्फ विविधता के लिए, यहां एक और समाधान है जो स्मृति को बचाता है। यह उन परिचालनों के लिए भी काम करेगा जिनके पास अंतर्निहित numpy समतुल्य नहीं है।

>>> values = numpy.array([(x % 2) for x in range(12)], dtype=bool).reshape((4,3)) 
>>> weights = numpy.array(range(1, 4)) 
>>> weights_stretched = numpy.lib.stride_tricks.as_strided(weights, (4, 3), (0, 8)) 

numpy.lib.stride_tricks.as_strided एक अद्भुत छोटा काम है! यह आपको shape और strides मान निर्दिष्ट करने की अनुमति देता है जो एक छोटी सी सरणी को एक बहुत बड़ी सरणी की नकल करने की अनुमति देता है। निरीक्षण करें - वास्तव में चार पंक्तियां नहीं हैं;

>>> weights_stretched[0][0] = 4 
>>> weights_stretched 
array([[4, 2, 3], 
     [4, 2, 3], 
     [4, 2, 3], 
     [4, 2, 3]]) 

बजाय MaskedArray के लिए एक विशाल सरणी से गुजर रहा है, आप एक छोटे से एक पारित कर सकते हैं: यह है कि अभी जिस तरह से लग रहा है। (लेकिन जैसा कि आपने पहले ही देखा है, numpy मास्किंग विपरीत तरीके से काम करता है, आप उम्मीद कर सकते हैं; सत्य मास्क, प्रकट करने के बजाए, इसलिए आपको अपना values उलटा करना होगा।) जैसा कि आप देख सकते हैं, MaskedArray किसी की प्रतिलिपि नहीं है डेटा; यह सिर्फ दर्शाता है जो कुछ weights_stretched में है:

>>> masked = numpy.ma.MaskedArray(weights_stretched, numpy.logical_not(values)) 
>>> weights_stretched[0][0] = 1 
>>> masked 
masked_array(data = 
[[-- 2 --] 
[1 -- 3] 
[-- 2 --] 
[1 -- 3]], 
     mask = 
[[ True False True] 
[False True False] 
[ True False True] 
[False True False]], 
     fill_value=999999) 

अब हम सिर्फ यह योग करने के लिए पारित कर सकते हैं:

>>> sum(masked, axis=1) 
masked_array(data = [2 4 2 4], 
     mask = [False False False False], 
     fill_value=999999) 

मैं numpy.dot बेंचमार्क और एक 1,000,000 x 30 सरणी के खिलाफ ऊपर। इस पर एक अपेक्षाकृत आधुनिक मैकबुक प्रो परिणाम है (numpy.dotdot1 है, मेरा dot2 है):

>>> %timeit dot1(values, weights) 
1 loops, best of 3: 194 ms per loop 
>>> %timeit dot2(values, weights) 
1 loops, best of 3: 459 ms per loop 

आप देख सकते हैं, निर्मित numpy समाधान तेजी से होता है। लेकिन stride_tricks परवाह किए बिना जानने योग्य है, इसलिए मैं इसे छोड़ रहा हूं।

+0

stride_tricks सुनिश्चित करने के लायक है! मुझे आश्चर्य हुआ कि ऐसा कुछ संभव था, और यह देखने की कोशिश की कि क्या संदर्भों द्वारा सरणी का निर्माण किया जा सकता है, लेकिन छोड़ दिया। मैं भविष्य में इसका उपयोग कर कल्पना कर सकता हूं, धन्यवाद! –

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