सबसे कुशल तरीका एक सुन्न सरणी रिवर्स करने के लिए


276

मानो या न मानो, मेरे वर्तमान कोड की रूपरेखा तैयार करने के बाद, सुन्न सरणी के दोहराव वाले संचालन ने चलने वाले समय के विशालकाय हिस्से को खा लिया। मेरे पास अभी जो सामान्य दृश्य-आधारित विधि है:

reversed_arr = arr[::-1]

क्या इसे और अधिक कुशलता से करने का कोई अन्य तरीका है, या क्या यह केवल मेरे जुनून से अवास्तविक संख्यात्मक प्रदर्शन का भ्रम है?


27
एर ... arr[::-1]बस एक उलटा दृश्य लौटाता है। यह उतना ही तेज़ है जितना कि आप प्राप्त कर सकते हैं, और यह सरणी में आइटम की संख्या पर निर्भर नहीं करता है, क्योंकि यह बस स्ट्रैड को बदलता है। क्या आप वास्तव में एक सुन्न सरणी उलट रहे हैं?
जो किंग जूल

हाँ, वास्तव में, arrएक संख्यात्मक सरणी है।
nye17

12
हम्म् ... खैर, मेरे लैपटॉप पर यह सरणी की लंबाई की परवाह किए बिना लगभग 670 नैनोसेकंड लेता है। यदि यह आपकी अड़चन है, तो आपको भाषाओं को स्विच करने की आवश्यकता हो सकती है ... मुझे पूरा यकीन है कि आपको एक सुस्पष्ट सरणी को उलटने का एक तेज़ तरीका नहीं मिलेगा। सौभाग्य, किसी भी दर पर!
जो किंग जूल

6
ठीक है, क्या आप जरूरी एक पाश के अंदर इसे चलाने के लिए है? कुछ मामलों में, लाखों वस्तुओं के साथ एक सुव्यवस्थित सरणी बनाना बेहतर होता है और फिर पूरे सरणी पर काम करते हैं। यहां तक ​​कि अगर आप एक परिमित अंतर विधि या ऐसा ही कुछ कर रहे हैं, जहां परिणाम पिछले परिणाम पर निर्भर करता है, तो आप कभी-कभी ऐसा कर सकते हैं। (कभी-कभी जोर ...) किसी भी दर पर, यदि गति प्राथमिक लक्ष्य है, तो फोरट्रान अभी भी राजा है। f2pyआपका दोस्त है! यह अक्सर एल्गोरिथ्म के प्रदर्शन के महत्वपूर्ण हिस्सों (विशेष रूप से वैज्ञानिक कंप्यूटिंग में) को किसी अन्य भाषा में लिखने और अजगर से इसे लिखने के लिए सार्थक है। सौभाग्य!
जो किंग जूल

1
@berto। यह धीमी है क्योंकि यह इसके लिए एक आवरण है arr[::-1]: github.com/numpy/numpy/blob/master/numpy/lib/twodim_base.py । के लिए खोजें def flipud। फ़ंक्शन का शाब्दिक अर्थ है चार लाइनें लंबी।
मैड फिजिसिस्ट

जवाबों:


239

जब आप बनाते हैं reversed_arrतो आप मूल सरणी में एक दृश्य बना रहे हैं। फिर आप मूल सरणी बदल सकते हैं, और दृश्य परिवर्तनों को प्रतिबिंबित करने के लिए अद्यतन करेगा।

क्या आप अपनी आवश्यकता से अधिक बार दृश्य बना रहे हैं? आपको ऐसा कुछ करने में सक्षम होना चाहिए:

arr = np.array(some_sequence)
reversed_arr = arr[::-1]

do_something(arr)
look_at(reversed_arr)
do_something_else(arr)
look_at(reversed_arr)

मैं एक खौफनाक विशेषज्ञ नहीं हूं, लेकिन ऐसा लगता है कि यह चीजों को सुन्न करने का सबसे तेज़ तरीका होगा। यदि यह आप पहले से ही कर रहे हैं, तो मुझे नहीं लगता कि आप इस पर सुधार कर सकते हैं।

पुनश्च यहाँ महान विचारों की महान चर्चा:

सुन्न सरणी पर देखें?


क्या यह एक स्लाइस ऑब्जेक्ट बनाने में मदद करता है और फिर कई सरणियों पर इसका पुन: उपयोग करता है?
एंडोलिथ

1
वास्तव में मैंने अभी इसका परीक्षण किया है और लूप के बाहर बनाई गई स्लाइस ऑब्जेक्ट के साथ कोई अंतर नहीं दिखता है। (ओह रुको, यह बहुत थोड़ा तेज है। 1000000 लूप के लिए 43.4 एमएस बनाम 44.3 एमएस।)
एंडोलिथ

look_atफ़ंक्शन मान क्या है ?
मर्ग्लोम

1
@mrgloom यह किसी भी कार्य का प्रतिनिधित्व करने वाला है जो डेटा को देखता है। उदाहरण का मुद्दा यह दिखाना था कि reversed_arrअंतर्निहित डेटा को बदलने के बाद दृश्य अभी भी प्रयोग करने योग्य है। सरणी में नए मान लिखना दृश्य को अमान्य नहीं करता है। वास्तव में आप व्यू में नए मान लिखने के लिए भी उपयोग कर सकते हैं। reversed_arr[0] = 99सरणी में अंतिम तत्व को 99 पर सेट करेगा, जैसा arr[-1] = 99होगा।
चरणवे

60

जैसा कि ऊपर उल्लेख किया गया है, a[::-1]वास्तव में केवल एक दृश्य बनाता है, इसलिए यह एक निरंतर-समय ऑपरेशन है (और जैसा कि सरणी बढ़ने में अधिक समय नहीं लगता है)। यदि आपको सरणी को सन्निहित होने की आवश्यकता है (उदाहरण के लिए क्योंकि आप इसके साथ कई वेक्टर संचालन कर रहे हैं), ascontiguousarrayलगभग उतना ही तेज़ है flipup/fliplr :

यहां छवि विवरण दर्ज करें


प्लॉट जनरेट करने के लिए कोड:

import numpy
import perfplot


perfplot.show(
    setup=lambda n: numpy.random.randint(0, 1000, n),
    kernels=[
        lambda a: a[::-1],
        lambda a: numpy.ascontiguousarray(a[::-1]),
        lambda a: numpy.fliplr([a])[0],
    ],
    labels=["a[::-1]", "ascontiguousarray(a[::-1])", "fliplr"],
    n_range=[2 ** k for k in range(25)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)

perfplot के लिए कम से कम अजगर 3.6 की आवश्यकता होती है क्योंकि इसमें f- स्ट्रिंग्स (लिटरल स्ट्रिंग इंटरपोलेशन) का उपयोग किया जाता है
पांच

42

क्योंकि यह अभी तक उत्तर के रूप में चिह्नित नहीं किया गया लगता है ... थॉमस अरिल्डसन का उत्तर उचित होना चाहिए: बस उपयोग करें

np.flipud(your_array) 

अगर यह एक 1d सरणी (स्तंभ सरणी) है।

मैट्रिज के साथ

fliplr(matrix)

यदि आप पंक्तियों को उलटना चाहते हैं और flipud(matrix)यदि आप स्तंभों को पलटना चाहते हैं। अपने 1d कॉलम सरणी को 2dimensional पंक्ति सरणी (एक परत के साथ मैट्रिक्स) बनाने और फिर इसे फ़्लिप करने के लिए कोई ज़रूरत नहीं है।


38

np.fliplr() सरणी को दाईं ओर छोड़ता है।

ध्यान दें कि 1d सरणियों के लिए, आपको इसे थोड़ा ट्रिक करने की आवश्यकता है:

arr1d = np.array(some_sequence)
reversed_arr = np.fliplr([arr1d])[0]

34
reversed_arr = np.flipud(arr1d)सीधे काम करने लगता है।
थॉमस एरिल्डसन

3

मैं पहले वाले उत्तर के बारे में विस्तार करूंगा np.fliplr()। यहाँ कुछ कोड है जो 1d सरणी का निर्माण दर्शाता है, इसे 2d सरणी में परिवर्तित करता है, इसे फ़्लिप करता है, फिर वापस 1d सरणी में परिवर्तित करता है। time.clock()समय रखने के लिए उपयोग किया जाएगा, जो सेकंड के संदर्भ में प्रस्तुत किया गया है।

import time
import numpy as np

start = time.clock()
x = np.array(range(3))
#transform to 2d
x = np.atleast_2d(x)
#flip array
x = np.fliplr(x)
#take first (and only) element
x = x[0]
#print x
end = time.clock()
print end-start

प्रिंट स्टेटमेंट के साथ:

[2 1 0]
0.00203907123594

प्रिंट स्टेटमेंट के साथ टिप्पणी की:

5.59799927506e-05

इसलिए, दक्षता के मामले में, मुझे लगता है कि यह सभ्य है। आप में से जो लोग इसे एक पंक्ति में करना पसंद करते हैं, उनके लिए यह रूप है।

np.fliplr(np.atleast_2d(np.array(range(3))))[0]

3
इतने छोटे सरणी के साथ कुछ समय निकालना बहुत बेकार है। यदि आप चीजों की तुलना करना चाहते हैं, तो कुछ समय का उपयोग करना बेहतर होगा, जैसे कि 3000 या शायद अधिक तत्व।
बाराबस

0

दूसरों ने जो कहा है उस पर विस्तार करते हुए मैं एक छोटा उदाहरण दूंगा।

यदि आपके पास 1D सरणी है ...

>>> import numpy as np
>>> x = np.arange(4) # array([0, 1, 2, 3])
>>> x[::-1] # returns a view
Out[1]: 
array([3, 2, 1, 0])

लेकिन अगर आप एक 2D सरणी के साथ काम कर रहे हैं ...

>>> x = np.arange(10).reshape(2, 5)
>>> x
Out[2]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> x[::-1] # returns a view:
Out[3]: array([[5, 6, 7, 8, 9],
               [0, 1, 2, 3, 4]])

यह वास्तव में मैट्रिक्स को उलट नहीं करता है।

वास्तव में तत्वों को उलटने के लिए np.flip का उपयोग करना चाहिए

>>> np.flip(x)
Out[4]: array([[9, 8, 7, 6, 5],
               [4, 3, 2, 1, 0]])

यदि आप मैट्रिक्स के तत्वों को एक-एक करके फ्लैट के साथ-साथ फ्लिप के साथ प्रिंट करना चाहते हैं

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0

-1

नकारात्मक संख्याओं और लंबी सूची के साथ काम करने के लिए आप निम्नलिखित कार्य कर सकते हैं:

b = numpy.flipud(numpy.array(a.split(),float))

जहां 1d arra के लिए flipud है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.