Garfield
YZF Admin
NumPy’de
Gerçek vektörleştirmede işlem, Python düzeyinde her eleman için ayrı ayrı çağrılmak yerine NumPy’nin derlenmiş iç döngüleriyle yürütülür. Toplama, çarpma, üs alma ve karşılaştırma gibi işlemler bu modele örnektir:
Burada
Çıktı aynı olsa da işleyiş farklıdır:
Aşağıdaki tablo, seçim yaparken önemli olan ayrımı özetler:
Tablodaki "vektörleştirilmiş" ifadesi her zaman aynı anlama gelmez. Bazı kütüphaneler bu sözcüğü yalnızca döngüyü gizlemek için kullanabilir. NumPy bağlamında performans açısından asıl soru, eleman başına çağrının Python’da mı kaldığı, yoksa işlemin derlenmiş bir iç döngüye mi taşındığıdır.
Örneğin bir değerin pozitifse karesini, değilse sıfırını döndürmek istediğinizi varsayalım. İşlem yalnızca NumPy işlemleriyle ifade edilebiliyorsa gerçek vektörleştirme daha uygundur:
Burada
Buna karşılık elinizde yalnızca tek bir değer alan, Python’da yazılmış ve NumPy işlemleriyle kolayca ifade edilemeyen bir fonksiyon varsa
Bu kod okunaklıdır ve çıktıyı üretir. Ancak
İşlem toplama, çarpma, karşılaştırma, üs alma, matematiksel fonksiyonlar veya koşullu seçim gibi NumPy işlemleriyle kurulabiliyorsa doğrudan dizi ifadelerini, ufunc’ları ve
İşlem çok karmaşıksa ve yalnızca küçük bir veri kümesinde okunabilirlik öncelikliyse
Performans gerçekten önemliyse aynı girdilerle birkaç yaklaşımı ölçün. Özellikle büyük dizilerde önce yerleşik NumPy ifadesini denemek, ardından gerekirse maskeleme, uygun veri türü veya başka bir derleme yaklaşımı değerlendirmek daha doğru bir sıradır.
np.vectorize(), bir işlemi gerçek anlamda vektörleştirmez; Python’daki bir fonksiyonu dizi elemanlarına tek tek uygulamak için kolay bir arayüz sağlar. Bu nedenle kodu daha okunaklı hâle getirebilir, ancak genellikle Python döngüsünün çalışma maliyetini ortadan kaldırmaz. Büyük dizilerde performans istiyorsanız önce NumPy’nin yerleşik dizi işlemlerini, ufunc’larını ve uygun olduğunda maskeleme yöntemlerini tercih edin; np.vectorize() ise daha çok küçük verilerde veya mevcut skaler fonksiyonu hızlıca diziyle uyumlu hâle getirmede kullanılmalıdır.İki yaklaşım arasındaki temel fark
Gerçek vektörleştirmede işlem, Python düzeyinde her eleman için ayrı ayrı çağrılmak yerine NumPy’nin derlenmiş iç döngüleriyle yürütülür. Toplama, çarpma, üs alma ve karşılaştırma gibi işlemler bu modele örnektir:
Python:
import numpy as np
x = np.array([1, 2, 3, 4])
y = x * 2 + 1
print(y)
# [3 5 7 9]
Burada
x * 2 + 1 ifadesi dizi işlemleriyle gerçekleştirilir. Python kodunda açık bir for döngüsü yazılmaz; asıl önemli nokta ise yalnızca sözdiziminin kısa olması değil, işlemin NumPy’nin düşük seviyeli, dizi odaklı kodundan yararlanmasıdır.np.vectorize() ise görünüşte aynı kullanım kolaylığını sağlar fakat verdiğiniz Python fonksiyonunu elemanlar için çağırır. Örneğin:
Python:
import numpy as np
def ikiyle_artir(deger):
return deger * 2 + 1
vektorlesmis = np.vectorize(ikiyle_artir)
x = np.array([1, 2, 3, 4])
y = vektorlesmis(x)
print(y)
# [3 5 7 9]
Çıktı aynı olsa da işleyiş farklıdır:
ikiyle_artir() Python fonksiyonu her eleman için çağrılır. Yani np.vectorize() kodu gerçek bir NumPy ufunc’ına dönüştürmez ve tek başına performans optimizasyonu sağlamaz.Aynı örneğin performans ve kullanım karşılaştırması
Aşağıdaki tablo, seçim yaparken önemli olan ayrımı özetler:
| Yaklaşım | Eleman işlemesi | Tipik kullanım | Performans beklentisi |
|---|---|---|---|
| NumPy yerleşik işlemi | NumPy’nin dizi işlemleriyle | x * 2 + 1, np.sqrt(x) | Genellikle en uygun seçenek |
| Yerleşik sayısal ufunc | Derlenmiş NumPy iç döngüsüyle | np.add(), np.sqrt() gibi işlemler | Uygun sayısal veri türlerinde eleman başına Python çağrısını azaltır |
np.vectorize() | Python fonksiyonu her eleman için çağrılarak | Skaler fonksiyonu hızlıca diziye uyarlama | Python döngüsüne benzer; hızlandırma garantisi yok |
| Açık Python döngüsü | Python kodundaki for döngüsüyle | Karmaşık ve koşullu işlemler | Büyük dizilerde çoğunlukla daha yavaş |
Somut kullanım sınırı
Örneğin bir değerin pozitifse karesini, değilse sıfırını döndürmek istediğinizi varsayalım. İşlem yalnızca NumPy işlemleriyle ifade edilebiliyorsa gerçek vektörleştirme daha uygundur:
Python:
import numpy as np
x = np.array([-2, -1, 0, 3])
y = np.where(x > 0, x ** 2, 0)
print(y)
# [0 0 0 9]
Burada
np.where() koşulu dizi üzerinde uygular. Sonuç, negatif ve sıfır değerlerin sıfıra; pozitif 3 değerinin ise 9’a dönüştüğünü gösterir. Bu örnekte np.vectorize() kullanmak gereksiz olurdu; çünkü işlem NumPy’nin yerleşik araçlarıyla doğrudan ifade edilebiliyor.Buna karşılık elinizde yalnızca tek bir değer alan, Python’da yazılmış ve NumPy işlemleriyle kolayca ifade edilemeyen bir fonksiyon varsa
np.vectorize() pratik olabilir:
Python:
import numpy as np
def etiketlendir(deger):
if deger < 0:
return "negatif"
if deger == 0:
return "sıfır"
return "pozitif"
x = np.array([-2, 0, 4])
y = np.vectorize(etiketlendir)(x)
print(y)
# ['negatif' 'sıfır' 'pozitif']
Bu kod okunaklıdır ve çıktıyı üretir. Ancak
otypes belirtilmediğinden NumPy çıktı türünü anlamak için ilk elemanı ayrıca dener; bu örnekte fonksiyon toplam dört kez çağrılır. Veri sayısı büyüdükçe bu yaklaşımın maliyeti artabilir. Ayrıca np.vectorize() fonksiyonun mantığını otomatik olarak daha hızlı hâle getirmez, bellek kullanımını kendiliğinden azaltmaz ve Python fonksiyonlarını derlenmiş NumPy koduna dönüştürmez.Hangisini seçmelisiniz?
İşlem toplama, çarpma, karşılaştırma, üs alma, matematiksel fonksiyonlar veya koşullu seçim gibi NumPy işlemleriyle kurulabiliyorsa doğrudan dizi ifadelerini, ufunc’ları ve
np.where() gibi araçları kullanın. Bu yaklaşım hem niyeti daha açık gösterir hem de NumPy’nin dizi işlemlerinden yararlanır.İşlem çok karmaşıksa ve yalnızca küçük bir veri kümesinde okunabilirlik öncelikliyse
np.vectorize() kullanılabilir. Ancak bunu bir hızlandırma tekniği olarak değil, mevcut skaler fonksiyona dizi benzeri bir çağrı arayüzü sağlayan kolaylık olarak değerlendirin.Performans gerçekten önemliyse aynı girdilerle birkaç yaklaşımı ölçün. Özellikle büyük dizilerde önce yerleşik NumPy ifadesini denemek, ardından gerekirse maskeleme, uygun veri türü veya başka bir derleme yaklaşımı değerlendirmek daha doğru bir sıradır.
np.vectorize() ile elde edilen daha kısa kod, tek başına daha hızlı kod anlamına gelmez.
Son düzenleme: