Bir numpy dizisini tersine çevirmenin en etkili yolu


276

İster inanın ister inanmayın, geçerli kodumun profilini oluşturduktan sonra, numpy dizi geri dönüşümünün tekrarlayan çalışması, çalışma süresinin dev bir yığınını yedi. Şu anda sahip olduğum ortak görünüm tabanlı yöntem:

reversed_arr = arr[::-1]

Daha verimli bir şekilde yapmanın başka bir yolu var mı, yoksa sadece gerçekçi olmayan numpy performansına olan takıntımdan bir yanılsama mı?


27
E ... arr[::-1]sadece ters bir görünüm döndürür. Olabildiğince hızlıdır ve dizideki öğelerin sayısına bağlı değildir, çünkü sadece adımları değiştirir. Ters çevirdiğiniz şey aslında bir dizi midir?
Joe Kington

evet, gerçekten arrde bir numpy dizisidir.
nye17

12
Hmmm ... Dizüstümün uzunluğu ne olursa olsun dizüstü bilgisayarımda yaklaşık 670 nanosaniye sürüyor. Bu sizin darboğunuzsa, dilleri değiştirmeniz gerekebilir ... Eminim bir numpy dizisini tersine çevirmenin daha hızlı bir yolunu bulamayacaksınız. Her neyse, iyi şanslar!
Joe Kington

6
Peki, mutlaka bir döngü içinde çalıştırmak zorunda mısınız? Bazı durumlarda, milyonlarca öğeyle sayısal bir dizi oluşturmak ve daha sonra tüm dizi üzerinde çalışmak daha iyidir. Sonlu fark yöntemi veya sonucun önceki sonuca bağlı olduğu yerde benzer bir şey yapsanız bile, bazen bunu yapabilirsiniz. (Vurgu bazen ...) Her halükarda, eğer hız birincil hedef ise, fortran hala kraldır. f2pysenin arkadaşın! Bir algoritmanın performans açısından kritik kısımlarını (özellikle bilimsel hesaplamada) başka bir dilde yazmak ve python'dan çağırmak genellikle faydalıdır. İyi şanslar!
Joe Kington

1
@berto. Bir paket olduğu için daha yavaştır arr[::-1]: github.com/numpy/numpy/blob/master/numpy/lib/twodim_base.py . İçin ara def flipud. İşlev tam anlamıyla dört satır uzunluğundadır.
Mad Physicist

Yanıtlar:


240

Oluşturduğunuzda reversed_arr, orijinal diziye bir görünüm oluşturursunuz. Daha sonra orijinal diziyi değiştirebilirsiniz; görünüm değişiklikleri yansıtacak şekilde güncellenir.

Görünümü, gerekenden daha sık yeniden oluşturuyor musunuz? Bunun gibi bir şey yapabilmelisiniz:

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

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

Ben numpy uzman değilim, ama bu numpy şeyler yapmak için en hızlı yolu gibi görünüyor. Eğer zaten yaptığınız şey buysa, bunu geliştirebileceğinizi düşünmüyorum.

PS Burada numpy görüşlerinin Büyük tartışma:

Bir numpy dizisi görüntülemek?


Bir dilim nesnesi oluşturmaya ve sonra bunu birçok dizide yeniden kullanmaya yardımcı olur mu?
endolit

1
Aslında ben sadece test ve döngü dışında oluşturulan dilim nesnesiyle herhangi bir fark görmüyorum. (Ah bekle, biraz daha hızlı. Tekrarlanabilir şekilde 43.4 ms vs 44.3 ms 1000000 döngü için)
endolit

look_atFonksiyon ne yapmalı?
mrgloom

1
@mrgloom Verilere bakan herhangi bir görevi temsil etmesi gerekiyor. Örneğin amacı reversed_arr, temel veriler değiştirildikten sonra görünümün hala kullanılabilir olduğunu göstermekti . Diziye yeni değerler yazmak görünümü geçersiz kılmaz. Aslında görünümü diziye yeni değerler yazmak için de kullanabilirsiniz. reversed_arr[0] = 99dizideki son öğeyi 99 ile aynı olacak şekilde ayarlardı arr[-1] = 99.
steveha

60

Yukarıda belirtildiği gibi, a[::-1]gerçekten sadece bir görünüm oluşturur, bu yüzden sabit zamanlı bir işlemdir (ve dizi büyüdükçe daha uzun sürmez). Dizinin bitişik olması gerekiyorsa (örneğin, onunla birçok vektör işlemi gerçekleştirdiğiniz için), / ascontiguousarraykadar hızlıdır :flipupfliplr

resim açıklamasını buraya girin


Grafiği oluşturmak için kod:

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 en az Python 3.6 gerektirir çünkü f-dizeleri kullanır (Değişmez Dize Enterpolasyonu)
fivef

42

Bu henüz cevaplanmış olarak işaretlenmemiş gibi görünüyor ... Thomas Arildsen'in cevabı uygun olmalı: sadece kullanın

np.flipud(your_array) 

1d dizisi ise (sütun dizisi).

Matrizes ile yapmak

fliplr(matrix)

satırları ters flipud(matrix)çevirmek ve sütunları ters çevirmek istiyorsanız. 1d sütun dizinizi 2 boyutlu bir satır dizisi (bir None katmanıyla matris) yapmaya ve sonra çevirmeye gerek yoktur.


38

np.fliplr() diziyi soldan sağa çevirir.

1d diziler için biraz kandırmanız gerektiğini unutmayın:

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

34
reversed_arr = np.flipud(arr1d)doğrudan çalışıyor gibi görünüyor.
Thomas Arildsen

3

Hakkında daha önceki cevabı genişleteceğim np.fliplr(). Burada, 1d dizisi oluşturmayı, 2d dizisine dönüştürmeyi, ters çevirmeyi ve sonra tekrar 1d dizisine dönüştürmeyi gösteren bazı kodlar bulunmaktadır. time.clock()saniye cinsinden sunulan zamanı tutmak için kullanılır.

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

Baskı ifadesi önerilmediğinde:

[2 1 0]
0.00203907123594

Yazdırılan ifadenin açıklaması ile:

5.59799927506e-05

Verimlilik açısından bence bu iyi. Bunu tek bir satırda yapmayı sevenleriniz için işte bu form.

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

3
Böyle küçük bir dizi ile bir şey zamanlamak oldukça işe yaramaz. Bir şeyleri karşılaştırmak istiyorsanız, 3000 veya belki daha fazla öğe gibi biraz zaman alan bir şey kullanmak daha iyi olurdu.
Barabas

0

Başkalarının söylediklerine genişleyerek kısa bir örnek vereceğim.

1D diziniz varsa ...

>>> 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])

Ama eğer 2B bir dizi ile çalışıyorsanız ...

>>> 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]])

Bu aslında Matrisi tersine çevirmez.

Öğeleri tersine çevirmek için np.flip kullanmalı

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

Bir matrisin öğelerini tek tek yazdırmak istiyorsanız, flip ile birlikte düz kullanın

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

-1

Negatif sayılar ve uzun bir liste ile çalışmasını sağlamak için aşağıdakileri yapabilirsiniz:

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

Flipud 1d arra için nerede

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.