26 Ekim 2014 Pazar

Numpy: Matrisler ve Basit Lineer Cebir

Sayısal analiz kitaplarının muhtevasını incelediğinizde fark ederseniz; birçoğu ilk bölümlerde doğrusal denklem sistemleri yani lineer cebir konusunu ele alır. Lineer cebirin bu kadar önemli olmasının sebebi, sayısal hesaplamaların çoğunun nihayetinde matris ve vektörlerden oluşan  doğrusal denklemlere indirgeniyor olmasıdır. Derslerimizin şu ana kadar ki kısımlarında genel olarak tek boyutlu vektörlerden bahsettik. Şimdi matrisleri biraz ayrıntılı irdeleyip Numpy kütüphanesini kullanarak temel lineer cebir işlemleri nasıl yapabileceğimiz öğrenelim.  
Matrisler
Matrisleri vektörler gibi oluşturabiliriz. Ancak matrislere özgü fonksiyonlar da mevcuttur. Bunları eye, identity, diag fonskiyonları olarak sıralayabiliriz. eye, identity fonksiyonları birbirine çok benzer olup birim matris oluşturmaya yarar.
>>> from numpy import *    # Numpy kütüphanesini ön alan adı eki olmadan ekliyoruz
>>> print(identity(3))     # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3))          # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3, k=1))     # köşegenin bir üst çapraza birim vektör ekleme 
[[ 0.  1.  0.]
 [ 0.  0.  1.]
 [ 0.  0.  0.]]
>>> print(eye(3, k=-2))    # köşegenin iki alt çapraza birim vektör ekleme 
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 1.  0.  0.]]
diag ise oldukça işlevsel bir fonksiyondur ve girilen bir vektörden köşegen matris oluşturur. Bu komut sayesinde aynı zamanda bant matrisleri de çok kolay oluşturabiliriz.
>>> print(diag([2,3,4], k=0))       # [2,3,4] dizisinden köşegen matris
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(diag([2,3,4], k=1))       # aynı diziden bir üst köşegen matris
[[0 2 0 0]
 [0 0 3 0]
 [0 0 0 4]
 [0 0 0 0]]
>>>
>>> # üçlü bant matris oluşturma
>>> print(diag(ones(4),k=-1) + diag(2*ones(5),k=0) + diag(ones(4), k=1))
[[ 2.  1.  0.  0.  0.]
 [ 1.  2.  1.  0.  0.]
 [ 0.  1.  2.  1.  0.]
 [ 0.  0.  1.  2.  1.]
 [ 0.  0.  0.  1.  2.]]

Lineer Cebire Giriş
Lineer cebir temel olarak matrislerin özelliklerini ve tek boyutlu vektörlerle olan işlemlerinin halidir. En genel halde bir lineer cebrik sistem A matris x ve b tek boyutlu vektör olmak üzere Ax=b şeklinde bir forma sahiptir. Bu sistemin çözülebilmesi için gerekli olan temel işleçler çarpım ve bölme işlemleridir. Matris-matris, matris-vektör çarpma/bölme işlemi bir önceki yazımızda anlattığımız vektörel aritmetikten farklı olup birebir elemanların çarpımı veya bölümüyle yapılmaz. O yüzden Numpy'de bu amaçla hususi fonksiyonlar tanımlanmıştır. Farkı anlamak için aşağıdaki örneklere göz atalım.
>>> A = ones((4,4))    # 1'lerden oluşan matris
>>> x = ones(4)        # 1'lerden oluşan vektör
>>> b = A*x            # matrisin her bir sütununun x ile vektörel çarpımı
>>> print(b)
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
>>> b = dot(A,x)      # lineer cebir çarpımı
>>> print(b)
[ 4.  4.  4.  4.]
Görüldüğü gibi ' operatörü bizim istediğimiz manada lineer cebir çarpımını değil vektörel formdaki çarpım işlevini yerini getirir. Bu yüzden Numpy'de matris-vektör çarpımı için dot fonksiyonu tanımlanmıştır. Benzer şekilde lineer cebrik sistemin çözümü için bölme işlemine yani x=b/A ifadesini hesaplayabilmemiz lazım. Bu işlem için yine direkt bölme operatörünü kullanmak yerine linalg alt kütüphanesi içerisindeki inv komutuyla matrisin tersini bulup b vektörüyle çarpabiliriz. 
>>> A = random.random((4,4))     # rastgele kare A matrisi
>>> print(A)
[[ 0.69769186  0.79776825  0.09984681  0.21271922]
 [ 0.05979394  0.72758335  0.0570817   0.59825989]
 [ 0.61698744  0.29374527  0.82004994  0.41084264]
 [ 0.02961924  0.86964469  0.63311203  0.82975882]]
>>> b = random.random(4)         # rastgele b vektörü
>>> print(b)
[ 0.20801453  0.81169016  0.84603751  0.74985329]<
>>>
>>> x = dot(linalg.inv(A), b)    # Ax=b çözümü olarak x=A^-1*b
>>> print(dot(A,x))              # bulduğumuz çözümün sağlamasını yapıyoruz (Ax=b) 
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Lineer sistemin çözümünü yukarıdaki gibi tersini alıp çarpmayla uğraşmak yerine linalg.solve komutunu kullanarak kısa yoldan gerçekleştirebiliriz.
>>> x = linalg.solve(A,b)
>>> print(dot(A,x))       # yine sağlamasını yapıp A*x=b olduğunu kontrol ediyoruz
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Üniversitede lineer cebir almış olanlar bilirler matrisin determinantı ve öz değer/vektörlerini kağı kalemle bulmak oldukça meşakkatlidir. Numpy'nin lineer cebir paketi sayesinde tek bir komutla bu işlemlerimizi basitçe halledebiliriz.
>>> A = diag([2,3,4], k=0)
>>> print(A)             # köşegen A matrisi
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(linalg.det(A)) # determinantı
24.0
>>> l, v = linalg.eig(A) # eig komutu öz değer ve öz vektörden oluşan iki döndürür
>>> print(l)             # öz değerler
[ 2.  3.  4.]
>>> print(v)             # öz vektörler yazdırılan matrisin sütunlarıdır
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
Oldukça geniş bir konu lineer cebrik sistemlere ilişkin yazımızı, Scipy kütüphanesinin konuları arasında daha fazla değinmek üzere şimdilik bitiriyoruz.

0 yorum :

Yorum Gönder