Uygulama Notları: 3

FİZ220 - Bilgisayar Programlama II | 20/03/2020

Matrisler (NumPy Matrix (numpy.matrix) Nesneleri)

Dr. Emre S. Taşcı, emre.tasci@hacettepe.edu.tr
Fizik Mühendisliği Bölümü
Hacettepe Üniversitesi

NumPy Kütüphanesine Giriş

NumPy ve SciPy kütüphaneleri

Python'da matematiksel işlemler için iki adet temel kütüphane vardır: NumPy ve SciPy. NumPy, temel matematik ve asıl olarak sayısal hesaplamaların olmazsa olmazı matris işlemlerini içerirken, SciPy daha ileri özel fonksiyonlarını ve çözüm yöntemlerini bünyesinde barındırır. Dersimizde işlemlerimize NumPy ile başlayıp, daha ileri seviyedeki problemler için ileride SciPy'dan da yararlanacağız.

NumPy nesneleri ve işlemleri, GNU Octave ile büyük parallellik gösterir. Bu benzerliği daha ilk aşamada "matrix" değişkeni ile hemen görmek mümkündür.

Matrix değişken tipi

NumPy'da matrix türündeki matrisler tırnak içinde, -tıpkı Octave'da olduğu gibi- sütunlar virgül veya boşlukla; satırlar ise noktalı virgülle ayrılır (Octave'ın aksine, satır ayrımı yapmak için bir alt satıra geçmek hataya sebep olur).

Tırnağın içerisinde köşeli parantez kullanmak opsiyoneldir.

3x3'lük bir matris tanımlayalım:

Temel Matris İşlemleri

Matris hakkında bilgi almak için kullanılan metotlar(*):

(*) Her ne kadar "metot" terimini kullanmış olsam da, teknik olarak matrix nesnesinin özelliklerinden ("attribute") bahsetmekteyiz -- işleri fazla karıştırmamak için nesne özellikleri ve metotları geçişli olarak kullanılacaktır.

Matris elemanlarına erişim ve değiştirme
Matris elemanlarına köşeli parantez içerisinde indisi belirterek erişebiliriz (indislerin 0'dan başladığına ve bütün indislerin aynı köşeli parantez içinde belirtildiğine dikkat edin!).

Örneğin, matrisimizin 2. satırının 3. elemanına erişmek için:

Matrisimizin bir kısmına erişmek için aralıkları kullanabiliriz:

Aralıkları belirtirken bitiş elemanının "kadar" anlamına geldiğini, onu içermediğini unutmayın!

Hazır aralıklardan söz açmışken, aralıklardaki artış miktarını 3. parametre olarak belirtiriz (GNU Octave'da bu parametre başlangıç ve bitiş parametrelerinin ortasında yer almaktaydı).

Transpozesini (devriğini) almak: 'T' metodu bu iş içindir:

Aynı işi uzun uzadıya transpose() fonksiyonu ile de yapabiliriz:

Fonksiyon NumPy kütüphanesinde tanımlı olduğundan, çağırırken 'np' isim alanı (namespace) ile np.transpose() şeklinde çağırdığımıza dikkat edin.

(Matrisin kompleks eşlenik transpozesini almak içinse 'H' metodu kullanılır)

Tersini (inverse) almak: 'I' metodu kullanılır:

Matrislerin birbirleri ile toplanması ve çarpılması
İki matris (boyutları uyumlu olduğu sürece) birbirleri ile toplanabilir, çarpılabilir (bir matrisin üssü de alınabilir).

(Sadece tam sayı üsler alınabilir -- örneğin matrisin kökünü hesaplamak için 0.5 üssünü kullanamayız -- biraz sabır, bu sorunun da üstesinden geleceğiz! 8)

Matrisin 'şeklini değiştirme':
Elimizde 3x4'lük bir matris olsun. Bu matrisin düzenini değiştirip, onu 6x2'lik bir matrise dönüştürmek istiyoruz. Bu durumda shape() metotu yardımımıza koşar:

Bazen de matrisimizi tamamıyla düzleştirmek yani onu 1 boyutlu bir matrise indirmek ihtiyacını duyarız. Bu durumda flat metotunu kullanırız:

flat metotu diğer metotların aksine bir matrix nesnesi değil, daha özel bir nesne (flatiter) döndürür (matrix nesnesi olmadığından ötürü de matrix nesnesinin sahip olduğu metotlara (örn. shape) sahip değildir). Bu nedenle yeni b matrisini tanımlarken b = np.matrix(a.flat) şeklinde, flatin sonucunu tekrardan matrix olarak atamaktayız.

Herhangi bir nesnenin cinsini type() fonksiyonu ile öğrenebiliriz:

Yolun Sonu

NumPy'ın matrix nesnesi çok başta, dil ilk kurulurken çalışmalara hız kazandırsın diye oluşturulmuş bir nesne idi: sonrasında yeterli gelmediği için, daha gelişmiş olan NumPy dizileri geliştirildi (bir sonraki dersimizin konusu).

Bu yetersizliği anlamak için, 1 boyutlu bir matrix nesnesi tanımlayalım:

buraya kadar bir sıkıntı yok.

Şimdi de 2 boyutlu bir matrix nesnesi tanımlayalım:

Hâlâ iyi gidiyoruz.

Daha da yüksek boyuta çıkalım:

Hata mesajına ("ValueError: matrix must be 2-dimensional"), hatta daha da açık olarak, orijinal tanımın içine yerleştirilmiş kontrol mekanizmasına ("if (ndim > 2):") bakacak olursanız, matrix nesnelerinin en fazla 2 boyutlu olabileceğini, daha yüksek boyutlara izin verilmediğini göreceksiniz.

Daha da dramatik olarak, bizzat resmi NumPy matrix nesnesinin dökümanında kullanıcı bu nesneye karşı uyarılmakta:

Note:

It is no longer recommended to use this class, even for linear algebra. Instead use regular arrays. The class may be removed in the future.

(Bu nesnenin lineer cebirde dahi kullanılması artık tavsiye edilmemektedir. Bunun yerine normal dizileri kullanın. Bu nesne gelecekte kaldırılabilir.)

Kurtuluş: NumPy dizileri

Biz ne yapacağız? Tavsiyeyi dinleyip, çok daha esnek ve daha geniş desteklenen NumPy dizilerini kullanacağız (bkz. bir sonraki ders). Elimizdeki bir matrix nesnesini doğrudan ve kolaylıkla NumPy dizisine çevirmek için 'A' metotu tanımlıdır:

Paniğe mahal yok: şimdiye kadar gördüğümüz pek çok matrix metodu NumPy dizilerinde de geçerlidir (olmayanlar da numpy.linalg kütüphanesi ile gelecek -- bir sonraki derste 8)

Aklınızdaki "o soru"

Madem ileride matrix nesnesini kullanmayıp dizileri (ndarray) kullanacaktık, ne demeye bu kadar şeyi gördük?

Programlama dillerinde dizi kavramı çok geniş bir kavram. Baştan o kapıdan geçseydik, "dizi... dizi..." dedikçe kafanız karışacaktı (çünkü NumPy'da dizi dediğimiz şey pratikte matrisin ta kendisi). Kaldı ki -bir sonraki derste göreceğimiz üzere- dizi tanımında bizim Octave'dan alışageldiğimiz ve matrislerde kullandığımız satır/sütun - noktalı virgül/virgül tanımına izin verilmemekte. Bu nedenle yumuşak bir geçiş olsun istedim. 'A' metotu yardımıyla hiçbir kayıp vermeden elimizdeki matrisleri hop diye diziye çevirebildiğimiz için, bu dersi dizilere bir giriş olarak ele aldık.

-Çok düşük ihtimalle de olsa- aklınızda olabilecek bir başka soru:

Hocam, "nesne... nesne..." (_object... object... ;) deyip duruyorsunuz, ama sonra type() fonksiyonu ile cinsini sorduğumuzda bize "bir şey bir şey sınıfı (class)" diye yanıt geliyor. Nesne ile sınıf arasındaki fark nedir?

(Öncelikle bu güzel soruyu sorduğunuz için teşekkür ederim... <kem küm...> 8) Sınıf dediğimiz şey, nesnenin ait olduğu yapıdır: nesne ise, bu yapıdan tanımladığımız bir elemandır, projeksiyon/anlık-gerçeklemedir (instance). Örneğin "araba" bir sınıftır: siz programınızda (hayatınızda) kullanmak üzere kendinize bu sınıftan bir eleman çektiğinizde (bir anlık-gerçekleme yaptığınızda) "Volkswagen", "Anadol", "Renault" gibi adı konulmuş bir nesne oluşturmuş olursunuz. Kafanız karıştıysa boşverin, teknik ve semantik bir ayrım var. Özetle: Sınıflar soyut (abstract) tanımlardır (üzerine binip bir yere gidemezsiniz), nesneler ise bu tanımlar doğrultusunda oluşturduğunuz, elle tutulur, üzerlerinde işlemler yapıp değerler atayabileceğiniz elemanlardır. Bu nedenle bir nesnenin cinsini sorduğumuzda cevap olarak onun sınıfı verilmektedir.