# NumPy
NumPy, Python programlama dili için büyük, çok boyutlu dizileri ve matrisleri destekleyen, bu diziler üzerinde çalışacak üst düzey matematiksel işlevler ekleyen bir kitaplıktır. NumPy'nin atası Numeric, ilk olarak Jim Hugunin tarafından diğer birkaç geliştiricinin katkılarıyla oluşturuldu. 2005 yılında Travis Oliphant, Numarray'in özelliklerini kapsamlı değişikliklerle Numeric'e dahil ederek NumPy'yi yarattı.
NumPy açık kaynaklı bir yazılımdır ve birçok katkıda bulunanlara sahiptir.


## Tarihçe.
Python programlama dili, başlangıçta sayısal hesaplama için tasarlanmamıştı ancak erken dönemlerde bilim ve mühendislik topluluğunun dikkatini çekti. 1995 yılında, bir dizi hesaplama paketini tanımlamak amacıyla özel ilgi grubu (special interest group) matrix-sig kuruldu; üyeleri arasında, dizi hesaplamayı kolaylaştırmak için Python'un sözdizimini (özellikle dizin oluşturma sözdizimini) genişleten Python tasarımcısı ve sürdürücü Guido van Rossum vardı.
Bir matris paketinin bir uygulaması Jim Fulton tarafından tamamlandı, daha sonra Jim Hugunin tarafından genelleştirildi ve Numeric olarak adlandırıld. ("Sayısal Python uzantıları (Numerical Python extensions)" veya "NumPy" olarak da bilinmektedir). Massachusetts Teknoloji Enstitüsü'nde yüksek lisans öğrencisi olan Hugunin, 1997 yılında JPython üzerinde çalışmak üzere Ulusal Araştırma Girişimleri Kurumuna (Corporation for National Research Initiatives) katıldı. Diğer erken katkıda bulunanlar arasında David Ascher, Konrad Hinsen ve Travis Oliphant yer aldı.
Numeric için daha esnek bir yedek olarak Numarray adlı yeni bir paket yazıldı. Numeric gibi, o da artık kullanımdan kaldırıldı. Numarray, büyük diziler için daha hızlı işlemlere sahipti, ancak küçük dizilerde Numeric'den daha yavaştı. Bu nedenle bir süre her iki paket de farklı kullanım durumları için paralel olarak kullanıldı. Numeric'in son sürümü (v24.2) 11 Kasım 2005'te, numarray'in son sürümü (v1.5.2) ise 24 Ağustos 2006'da yayınlandı.
Numeric'i Python standart kütüphanesine sokma arzusu vardı, ancak Guido van Rossum, kodun o zamanki durumunda korunamayacağına karar verdi.
2005'in başlarında, NumPy geliştiricisi Travis Oliphant, topluluğu tek bir dizi paketi etrafında birleştirmek istedi ve Numarray'in özelliklerini Numeric'e taşıdı. Bunun sonucunda 2006'da NumPy 1.0 olarak yayınlandı. Bu yeni proje SciPy'nin bir parçasıydı. Sadece bir dizi nesnesi elde etmek için büyük SciPy paketi kurmak yerine bu yeni paket ayrıldı ve NumPy olarak adlandırıldı. Python3 desteği 2011'de NumPy sürüm 1.5.0 ile eklendi.
2011'de PyPy, PyPy için NumPy API'sinin bir uygulaması üzerinde geliştirmeye başladı. NumPy ile henüz tam uyumlu değildi.


## Özellikleri.
NumPy, optimize etmeyen bir bayt kodu yorumlayıcısı olan Python'un CPython referans uygulamasını hedeflemektedir. Python'un bu sürümü için yazılan matematiksel algoritmalar, genellikle derlenmiş eşdeğerlerinden çok daha yavaş çalışmaktadır. NumPy, çok boyutlu diziler ve diziler üzerinde verimli çalışan işlevler ve operatörler sağlayarak yavaşlık sorununu kısmen ele alır. Bunları yapmak için NumPy kullanarak, çoğunlukla iç döngüler olmak üzere bazı kodların yeniden yazılmasını gerekmektedir.
Python'da NumPy kullanmak, her ikisi de yorumlandığından MATLAB ile karşılaştırılabilir işlevsellik sağlamaktadır. Çoğu işlem skalerler yerine diziler veya matrisler üzerinde çalıştığı sürece, her ikisi de kullanıcının hızlı programlar yazmasına izin vermektedir. Her ikisi karşılaştırıldığında, MATLAB çok sayıda ek araç kutusuna, özellikle Simulink'e sahiptir, oysa NumPy daha modern ve eksiksiz bir programlama dili olan Python ile entegredir. Ayrıca, tamamlayıcı Python paketleri mevcuttur; SciPy, daha fazla MATLAB benzeri işlevsellik ekleyen bir kütüphanedir. Ayrıca Matplotlib, MATLAB benzeri çizim işlevselliği sağlayan bir çizim paketidir. Dahili olarak, hem MATLAB hem de NumPy, verimli lineer cebir hesaplamaları için BLAS ve LAPACK'e güvenmektedir
Yaygın olarak kullanılan bilgisayarlı görü kitaplığı OpenCV'nin Python verilerini depolamak ve üzerinde çalışmak için NumPy dizilerini kullanmaktadır. Birden çok kanala sahip görüntüler basitçe üç boyutlu diziler olarak temsil edildiğinden, indeksleme, dilimleme veya diğer dizilerle maskeleme, bir görüntünün belirli piksellerine erişmenin çok etkili yollarıdır. OpenCV'de görüntüler, çıkarılan özellik noktaları, filtre çekirdekleri ve daha pek çok şey için evrensel veri yapısı olarak NumPy dizisi, programlama iş akışını ve hata ayıklamayı büyük ölçüde basitleştirmektedir.


### ndarray veri yapısı.
NumPy'nin temel işlevi, n-boyutlu dizi veri yapısı için "ndarray"idir. Bu diziler, bellekte adım adım görünümlerdir. Python'un yerleşik liste veri yapısının aksine, bu diziler homojen olarak yazılmaktadır. Tek bir dizinin tüm elemanları aynı tipte olmalıdır.
Bu tür diziler ayrıca C/C++, Cython ve Fortran uzantıları tarafından CPython yorumlayıcısına ayrılan bellek arabelleklerine, veri kopyalamaya gerek kalmadan mevcut sayısal kitaplıklarla bir dereceye kadar uyumluluk sağlayan görünümler olabilmektedir. Bu işlevsellik, bu tür kitaplıkları (özellikle BLAS ve LAPACK) saran SciPy paketi tarafından kullanılmaktadır. NumPy, bellek eşlemeli ndarray'ler için yerleşik desteğe sahiptir.


### Sınırlamalar.
Bir diziye giriş eklemek, Python listelerinde olduğu kadar kolay bir şekilde mümkün değildir. Dizileri genişletmek için yolu aslında istenen şekil ve dolgu değerlerine sahip yeni diziler yaratmaktadır. Ayrıca verilen diziyi yenisine kopyalar ve yeni diziyi döndürmektedir. NumPy'nin işlemi aslında iki diziyi birbirine bağlamaz, ancak sırayla verilen her iki dizideki girişlerle dolu yeni bir tane döndürmektedir. Bir dizinin boyutsallığını ile yeniden şekillendirmek ancak dizideki eleman sayısı değişmediği sürece mümkündür.
Bu koşullar, NumPy'nin dizilerinin bitişik bellek arabelleklerinde görünümler olması gerektiği gerçeğinden kaynaklanmaktadır. Blaze adlı bir değiştirme paketi bu sınırlamayı aşmaya çalışmaktadır.
Vektörleştirilmiş bir işlem olarak ifade edilemeyen algoritmalar, "saf Python"da uygulanmaları gerektiğinden daha yavaş çalışmaktadır. Vektörleştirme ise bazı işlemlerin bellek karmaşıklığını sabitten doğrusala yükseltebilmektedir. Çünkü girdiler kadar büyük olan geçici diziler oluşturulmalıdır. Sayısal kodun çalışma zamanı derlemesi, bu sorunlardan kaçınmak için birkaç grup tarafından uygulanmıştır. NumPy ile birlikte çalışan açık kaynaklı çözümler arasında , numepr ve Numba bulunmaktadır. Cython ve Pythran bunlara statik derleme alternatifleridir.
Birçok modern büyük ölçekli bilimsel hesaplama uygulamasının, NumPy dizilerinin yeteneklerini aşan gereksinimleri vardır. Örneğin, NumPy dizileri genellikle büyük veri kümelerinin analizi için yetersiz kapasiteye sahip olabilecek bir bilgisayarın belleğine yüklenmektedir. Ayrıca NumPy işlemleri tek bir CPU üzerinde yürütülmektedir. Bununla birlikte, birçok doğrusal cebir işlemi, CPU kümelerinde veya birçok derin öğrenme uygulamasının güvendiği GPU'lar ve TPU'lar gibi özel donanımlarda yürütülerek hızlandırılabilmektedir.
Sonuç olarak, son yıllarda bilimsel Python ekosisteminde dağıtılmış diziler için Dask ve GPU'lardaki hesaplamalar için TensorFlow veya JAX gibi çeşitli alternatif dizi uygulamaları ortaya çıkmıştır. Popülaritesi nedeniyle, bunlar genellikle Numpy'nin API'sinin bir alt kümesini uygulamaktadır veya onu taklit etmektedir. Böylece kullanıcılar kodlarında gereken minimum değişiklikle dizi uygulamalarını değiştirebilmektedir. Nvidia'nın CUDA çerçevesi tarafından hızlandırılan ve yakın zamanda tanıtılan CUPy adlı bir kitaplık, NumPy'nin 'açılan bir ikamesi' olarak daha hızlı bilgi işlem potansiyeli göstermiştir.


## Örnekler.
### Dizi(Array) oluşturma.
import numpy as np 
x = np.array([1, 2, 3])
print(x)
 - array([1, 2, 3])
y = np.arange(10)
print(y)
 - array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])


### Basit operatörler.
a = np.array([1, 2, 3, 6])
b = np.linspace(0, 2, 4)
c = a - b
print(c)
 - array([ 1., 1.33333333, 1.66666667, 4.])
print(a**2)
 - array([ 1, 4, 9, 36])


### Evrensel fonksiyonlar.
a = np.linspace(-np.pi, np.pi, 100) 
b = np.sin(a)
c = np.cos(a)


### Lineer cebir.
from numpy.random import rand
from numpy.linalg import solve, inv
a = np.array(1, 2, 3], [3, 4, 6.7], [5, 9.0, 5)
a.transpose()
print(a)
 - array( 1. , 3. , 5. ],
  - [ 2. , 4. , 9. ],
  - [ 3. , 6.7, 5. )
print(inv(a))
 - array(-2.27683616, 0.96045198, 0.07909605],
  - [ 1.04519774, -0.56497175, 0.1299435 ],
  - [ 0.39548023, 0.05649718, -0.11299435)
b = np.array([3, 2, 1])
print(solve(a, b)) # ax = b denklemini çöz
 - array([-4.83050847, 2.13559322, 1.18644068])
c = rand(3, 3) * 20 # 20 ile ölçeklenmiş [0,1] içinde 3x3 rastgele değerler matrisi oluşturun
print(c)
 - array( 3.98732789, 2.47702609, 4.71167924],
  - [ 9.24410671, 5.5240412 , 10.6468792 ],
  - [ 10.38136661, 8.44968437, 15.17639591)
print(np.dot(a, c)) # matris çarpımı
 - array( 53.61964114, 38.8741616 , 71.53462537],
  - [ 118.4935668 , 86.14012835, 158.40440712],
  - [ 155.04043289, 104.3499231 , 195.26228855)


### Tensörler.
M = np.zeros(shape=(2, 3, 5, 7, 11))
T = np.transpose(M, (4, 2, 1, 3, 0))
print(T.shape)
 - (11, 5, 3, 7, 2)