मैं विचार के "फॉर-लूप" स्कूल से कैसे दूर हो सकता हूं?


79

यह एक वैचारिक प्रश्न है, लेकिन मुझे उम्मीद थी कि मुझे इस पर कुछ अच्छी सलाह मिल सकती है। मेरे द्वारा की जाने वाली बहुत सी प्रोग्रामिंग ( NumPy ) सरणियों के साथ है; मुझे अक्सर दो या अधिक सरणियों में आइटम का मिलान करना पड़ता है जो अलग-अलग आकार के होते हैं और पहली चीज जो मैं जाता हूं वह है एक लूप या इससे भी बदतर, एक नेस्टेड-लूप। मैं यथासंभव लूप से बचना चाहता हूं, क्योंकि वे धीमे (कम से कम पायथन में) हैं।

मुझे पता है कि NumPy के साथ बहुत सी चीजों के लिए पूर्व-निर्धारित कमांड हैं जिन्हें मुझे बस शोध करने की आवश्यकता है, लेकिन क्या आपको (अधिक अनुभवी प्रोग्रामर के रूप में) एक सामान्य विचार प्रक्रिया है जो किसी चीज़ को पुनरावृत्त करने के लिए आपके दिमाग में आती है?

इसलिए मेरे पास अक्सर ऐसा कुछ होता है, जो भयानक होता है और मैं इससे बचना चाहता हूं:

small_array = np.array(["one", "two"])
big_array = np.array(["one", "two", "three", "one"])

for i in range(len(small_array)):
    for p in range(len(big_array)):
        if small_array[i] == big_array[p]:
            print "This item is matched: ", small_array[i]

मुझे पता है कि विशेष रूप से इसे प्राप्त करने के लिए कई अलग-अलग तरीके हैं, लेकिन मुझे लगता है कि यह मौजूद है, तो सामान्य तरीके से सोचने में दिलचस्पी है।


10
आप कार्यात्मक प्रोग्रामिंग की तलाश कर रहे हैं : लैम्ब्डा एक्सप्रेशन, उच्च-क्रम फ़ंक्शन, एक्सप्रेशन एक्सप्रेशन आदि।
किलन फ़ॉथ

42
I want to avoid for-loops as much as possible because they are slow (at least in Python).लगता है कि आप यहाँ गलत समस्या को हल कर रहे हैं। यदि आपको किसी चीज़ पर पुनरावृति करने की आवश्यकता है, तो आपको किसी चीज़ पर पुनरावृति करने की आवश्यकता है; आप इसी तरह का प्रदर्शन करेंगे, जिससे कोई फर्क नहीं पड़ता कि आप किस पायथन का उपयोग करते हैं। यदि आपका कोड धीमा है, तो यह नहीं है क्योंकि आपके पास forलूप हैं; यह इसलिए है क्योंकि आप अनावश्यक काम कर रहे हैं या पायथन साइड पर काम कर रहे हैं जो सी साइड पर किया जा सकता है। अपने उदाहरण में आप अतिरिक्त काम कर रहे हैं; आप इसे दो के बजाय एक लूप के साथ कर सकते हैं।
डोभाल

24
@ डोवाल दुर्भाग्य से नहीं - न्यूमपी में । एलिमेंटली न्यूमपाइ ऑपरेटर (जो न केवल C में लिखा गया है, बल्कि SSE के निर्देशों और अन्य ट्रिक्स का उपयोग करता है) की तुलना में वास्तविक रूप से आकार के लिए लूप के लिए पायथन आसानी से कई बार (!) धीमा हो सकता है।

46
उपरोक्त कुछ टिप्पणियाँ प्रश्न को गलत समझती हैं। NumPy में प्रोग्रामिंग करते समय, आपको सबसे अच्छे परिणाम मिलते हैं यदि आप अपनी गणना को वेक्टर कर सकते हैं - अर्थात, PyPon में स्पष्ट छोरों को NumPy में पूरे-सरणी संचालन से बदल दें। यह पायथन में सामान्य प्रोग्रामिंग से वैचारिक रूप से बहुत अलग है, और सीखने में समय लगता है। इसलिए मुझे लगता है कि यह ओपी के लिए उचित है कि वह इसे करने के लिए सीखने के बारे में सलाह ले।
गारेथ रीस

3
@ पीटर: हाँ, यह सही है। "वैश्वीकरण" "सर्वश्रेष्ठ एल्गोरिथ्म चुनने" के समान नहीं है। वे कुशल कार्यान्वयन के साथ आने में कठिनाई के दो अलग-अलग स्रोत हैं और इसलिए एक बार में उनके बारे में सोचना सबसे अच्छा है।
गैरेथ रीस

जवाबों:


89

यह एक सामान्य वैचारिक कठिनाई है जब प्रभावी रूप से NumPy का उपयोग करना सीखते हैं । आम तौर पर, पायथन में डेटा प्रोसेसिंग को पुनरावृत्तियों के रूप में सबसे अच्छा व्यक्त किया जाता है , स्मृति उपयोग को कम रखने के लिए, I / O प्रणाली के साथ समानता के अवसरों को अधिकतम करने के लिए, और एल्गोरिदम के कुछ हिस्सों के पुन: उपयोग और संयोजन के लिए प्रदान किया जाता है।

लेकिन NumPy वह सब अंदर बाहर करता है: सबसे अच्छा तरीका एल्गोरिथ्म को पूरे-सरणी संचालन के अनुक्रम के रूप में व्यक्त करना है , धीमी गति से अजगर दुभाषिया में बिताए समय की मात्रा को कम करना और तेजी से संकलित NumPon दिनचर्या में बिताए गए समय की मात्रा को अधिकतम करना है।

यहाँ सामान्य दृष्टिकोण मैं ले रहा हूँ:

  1. फ़ंक्शन के मूल संस्करण (जो आपको विश्वास है कि सही है) को सुरक्षित रखें ताकि आप शुद्धता और गति दोनों के लिए अपने उन्नत संस्करणों के खिलाफ इसका परीक्षण कर सकें।

  2. अंदर से बाहर काम करें: अर्थात्, अंतरतम लूप से शुरू करें और देखें कि क्या इसे सदिश किया जा सकता है; तब जब आप ऐसा कर चुके होते हैं, तो एक स्तर आगे बढ़ाते हैं और जारी रखते हैं।

  3. NumPy प्रलेखन को पढ़ने में बहुत समय व्यतीत करें । वहाँ बहुत सारे फ़ंक्शंस और ऑपरेशन हैं और उन्हें हमेशा शानदार ढंग से नाम नहीं दिया जाता है, इसलिए उन्हें जानना योग्य है। विशेष रूप से, यदि आप अपने आप को यह सोचते हुए पाते हैं, "यदि केवल एक ऐसा कार्य होता है जो ऐसा-और-ऐसा करता है," तो यह दस मिनट बिताने के लायक है। यह आमतौर पर वहाँ कहीं है।

अभ्यास का कोई विकल्प नहीं है, इसलिए मैं आपको कुछ उदाहरण समस्याएं देने जा रहा हूं। प्रत्येक समस्या के लिए लक्ष्य फ़ंक्शन को फिर से लिखना है ताकि यह पूरी तरह से वेक्टरित हो जाए : अर्थात् , ताकि पूरे एरेज़ पर न्यूमिपी ऑपरेशंस का एक अनुक्रम शामिल हो, जिसमें कोई देशी पायथन लूप्स (कोई forया whileस्टेटमेंट्स, कोई पुनरावृत्तियाँ या समझ नहीं) हों।

समस्या 1

def sumproducts(x, y):
    """Return the sum of x[i] * y[j] for all pairs of indices i, j.

    >>> sumproducts(np.arange(3000), np.arange(3000))
    20236502250000

    """
    result = 0
    for i in range(len(x)):
        for j in range(len(y)):
            result += x[i] * y[j]
    return result

समस्या २

def countlower(x, y):
    """Return the number of pairs i, j such that x[i] < y[j].

    >>> countlower(np.arange(0, 200, 2), np.arange(40, 140))
    4500

    """
    result = 0
    for i in range(len(x)):
        for j in range(len(y)):
            if x[i] < y[j]:
                result += 1
    return result

समस्या 3

def cleanup(x, missing=-1, value=0):
    """Return an array that's the same as x, except that where x ==
    missing, it has value instead.

    >>> cleanup(np.arange(-3, 3), value=10)
    ... # doctest: +NORMALIZE_WHITESPACE
    array([-3, -2, 10, 0, 1, 2])

    """
    result = []
    for i in range(len(x)):
        if x[i] == missing:
            result.append(value)
        else:
            result.append(x[i])
    return np.array(result)

नीचे स्पॉइलर। यदि आप मेरे समाधानों को देखने से पहले स्वयं जाते हैं तो आपको बहुत अच्छे परिणाम मिलेंगे!

उत्तर 1

np.sum (x) * np.sum (y)

उत्तर २

np.sum (np.searchsorted (np.sort (x), y))

उत्तर ३

np.where (x == लापता, मान, x)


रुको, क्या अंतिम उत्तर में एक टाइपो है या क्या NumPy संशोधित करता है कि पायथन कोड की व्याख्या कैसे करता है?
इज़काता

1
@ इजाका यह प्रति सेगमेंट को कुछ भी संशोधित नहीं करता है, लेकिन ब्रेसिज़ सरणियों को वापस करने के लिए लागू किए गए तार्किक संचालन को परिभाषित किया जाता है।
सपि

@sapi आह, मुझे याद आया कि क्या क्या चल रहा है, सोचा था कि वे सादे थेlist
इज़काता

शायद एपीएल को एम्बेड करने का एक तरीका होना चाहिए?

मुझे पसंद है कि आप होमवर्क कैसे देते हैं।
कोरे तुगे

8

चीजों को तेज करने के लिए आपको अपने डेटा संरचनाओं पर पढ़ना होगा और लोगों को उपयुक्त का उपयोग करना होगा।

छोटे सरणी और बड़े सरणी के गैर तुच्छ आकारों के लिए (मान लें कि छोटे = 100 तत्व और बड़े = 10.000 तत्व) ऐसा करने का एक तरीका यह है कि छोटे सरणी को सॉर्ट करें, फिर बड़े-सरणी पर पुनरावृति करें और मिलान तत्वों को खोजने के लिए एक द्विआधारी खोज का उपयोग करें छोटे सरणी में।

इससे अधिकतम समय जटिलता हो जाएगी, O (N log N) (और छोटे छोटे-सरणियों के लिए और बहुत बड़े-बड़े सरणियों के लिए यह O (N) के करीब है) जहां आपका नेस्टेड लूप समाधान O (N ^ 2) है

हालाँकि। क्या डेटा संरचनाएं सबसे अधिक कुशल हैं यह वास्तविक समस्या पर अत्यधिक निर्भर है।


-3

प्रदर्शन को अनुकूलित करने के लिए आप शब्दकोश का उपयोग कर सकते हैं

यह एक और उदाहरण है:

locations = {}
for i in range(len(airports)):
    locations[airports["abb"][i][1:-1]] = (airports["height"][i], airports["width"][i])

for i in range(len(uniqueData)):
    h, w = locations[uniqueData["dept_apt"][i]]
    uniqueData["dept_apt_height"][i] = h
    uniqueData["dept_apt_width"][i] = w

2
यह काफी स्पष्ट रूप से अभी भी सोचा के "फॉर-लूप" स्कूल का उपयोग कर रहा है।
8bittree
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.