NumPy’ye Giriş — 1
Python’da Veri Türlerini Anlamak
Etkili bir veri bilimci olmak, verilerin nasıl depolandığını ve manipüle edildiğini anlamayı beraberinde getirir. Bu bölümde, veri dizelerinin Python dilinde nasıl işlendiğini ve NumPy’nin bunu nasıl geliştirdiğini ana hatlarıyla anlayacağız.
Python, dinamik veya “duck” denilen ara kod yazımını kullanır. C veya Java gibi statik olarak yazılan bir dil, her değişkenin açıkça bildirilmesini gerektirirken, Python gibi dinamik olarak yazılan bir dil bu belirtimi atlar. Örneğin, C’de belirli bir işlemi aşağıdaki gibi belirtebilirsiniz:
Python’dayken eşdeğer işlem şu şekilde yazılabilir:
Burada ki temel farka dikkat edelim: C’de, her değişkenin veri türü açıkça bildirilirken, Python’da türler dinamik olarak çıkarılır. Bu örneğe bakarsak Python’da herhangi bir değişkene herhangi bir veri türü atayabileceğimiz anlamına gelir:
Burada
x değişkenini bir tamsayıdan bir dizgiye çevirdik . C’deki aynı şey (derleyici ayarlarına bağlı olarak) bir derleme hatasına veya diğer istenmeyen sonuçlara yol açabilir:
Bu tür bir esneklik, Python ve diğer dinamik olarak yazılan dilleri kullanışlı ve kullanımı kolay hale getirir. Bunun nasıl çalıştığını anlamak , verileri Python ile verimli ve etkili bir şekilde analiz etmeyi öğrenmenin önemli bir parçasıdır. Ancak bu tip esnekliğinin bize gösteriyor ki, Python da yaratılan değişkenler değerlerinden daha fazlasını içerir; ayrıca değerin türü hakkında ek bilgiler mevcuttur. Bunu ilerleyen bölümlerde daha fazla keşfedeceğiz.
Bir Python Tam Sayısı, Bir Tam Sayıdan Daha Fazlasıdır
Python tutorial’da Python’un orijinal uygulamasının C dilinde olduğu okunabilir. Bu, her Python nesnesinin yalnızca değerini değil, aynı zamanda diğer bilgileri de içeren akıllıca gizlenmiş bir C yapısı olduğu anlamına gelir. Örneğin Python’da bir tamsayı tanımladığımızda, örneğin
x = 10000,
xsadece bir “ham” tamsayı değildir. Aslında, birkaç değer içeren bileşik C yapısının bir göstergesidir. Python 3.4 kaynak koduna baktığımızda, integer (long) tip tanımının etkin bir şekilde şöyle göründüğünü görüyoruz.
Python 3.4’teki tek bir tamsayı aslında dört parça içerir:
ob_refcnt, Python’un bellek geri dönüşüm mekanizması, referans sayma mekanizmasını kullanır. Geçerli nesneye kaç kez başvurulduğunu saymak için bir ob_refcnt vardır.
ob_typedeğişkenin türünü kodlar
ob_size, ob_digit içindeki öğelerin sayısını tutar
ob_digitbasamak türünde bir dizidir. Python belleği ob_digit dizisine göre ayırırken daha verimli olmak için, aşırı provizyon(ön onay) yapar ve ardından dizide tutulan gerçek öğe sayısını belirlemek için ob_size değerine güvenir.
Aşağıdaki şekilde gösterildiği gibi, C gibi derlenmiş bir dilde(compiled languages) bir tamsayıya kıyasla Python’da bir tamsayı depolamanın bir miktar ek yükü olduğu anlamına gelir:
compiled languages : kaynak kod doğrudan hedef makine tarafından çevrilir.
interpreted language: kaynak kod doğrudan hedef makine tarafından çevrilmez. Bunun yerine, farklı bir program, yani yorumlayıcı, kodu okur ve yürütür.
Burada
PyObject_HEAD yapının referans sayısı, tip kodunu ve daha önce bahsedilen diğer parçaları içeren kısmı tutar.
Buradaki farka dikkat edin: Aslında bir C tamsayısı, bellekteki bir konumu gösteren bir etikettir. Bu bellekte bir tam sayının değerini tutan baytlar bulunur. Lakin bir Python tamsayısı, tamsayının değerini içeren baytlar da dahil olmak üzere tüm Python nesnesinin bilgilerini içeren, bellekteki bir konumu gösteren bir işaretçidir. Bu tamsayı yapısındaki ekstra bilgi, Python’un bu kadar özgür ve dinamik bir şekilde kodlanmasını sağlar. Python türlerindeki tüm bu ek bilgilerin bir maliyeti vardır. Ancak bu, özellikle bu nesnelerin çoğunu kombine eden yapılarda belirgin hale gelir.
Bir Python Listesi, Bir Listeden Daha Fazlasıdır
Birden fazla Python nesnesini tutan bir Python veri yapısı kullandığımızda ne olduğunu düşünelim. Python’daki standart değişken çok elemanlı kap, listedir. Aşağıdaki gibi bir tamsayı listesi oluşturabiliriz:
veya benzer şekilde bir string listesine bakalım:
Python’un dinamik yazma özelliği sayesinde, heterojen listeler bile oluşturabiliriz:
Tabiki de bu esnekliğin bir bedeli vardır: Python bu esnek türlere izin vermek için listedeki her öğenin kendi tür bilgisini, referans sayısını ve diğer bilgileri depolar. Yani her öğe eksiksiz bir Python nesnesi olarak tutulur. Tüm değişkenlerin aynı türde olduğu özel durumlarda, bu bilgilerin çoğu gereksizdir: verileri sabit türde bir dizide depolamak çok daha verimli olabilir. Dinamik tipli bir liste ile sabit tipli (NumPy tarzı) bir dizi arasındaki fark aşağıdaki şekilde gösterilmektedir:
Numpy Array, bir bitişik veri bloğuna tek bir işaretçi ile erişir. Öte yandan Python listesi, her biri daha önce gördüğümüz Python tamsayısına benzer bir Python nesnesine işaret eden bir işaretçi(ler) bloğuna bir işaretçi(items) içerir. Yine de python listenin avantajı esnekliktir: her liste elemanı hem veri hem de tip bilgisi içeren tam bir yapı olduğundan, liste istenilen herhangi bir tipte veri ile doldurulabilir. NumPy tarzı sabit tipteki diziler bu esneklikten yoksundur, ancak verileri depolamak ve işlemek için çok daha verimlidir.
Python’da Sabit Tip Diziler
Python, verileri verimli ve sabit bir tipte arabelleklerinde depolamak için birkaç farklı seçenek sunar. Yerleşik
arraytek tip diziler oluşturmak için kullanılabilir (Python 3.3 ve sonrasında mevcuttur) modülü:
Burada ki
'i'içeriğin tamsayı(integer) olduğunu gösteren bir tür kodu.
Ancak
ndarrayNumPy paketinin nesnesi çok daha kullanışlıdır . Python’un
arraynesnesi, dizi tabanlı verilerin verimli bir şekilde depolanmasını sağlarken, NumPy bu veriler üzerinde verimli işlemlerin yapılmasını sağlar . Bu işlemleri sonraki bölümlerde inceleyeceğiz; burada bir NumPy dizisi oluşturmanın birkaç yolunu göstereceğiz.
Python Listelerinden Dizi Oluşturma
Öncelikle NumPy kütüphanesini içeri aktaracağız (“np” kısaltması ile). Daha sonra
np.array kullanarak Python listelerinden diziler oluşturabiliriz:
Python listelerinden farklı olarak NumPy’nin tümü aynı türde dizilerle sınırlı olduğunu unutmayın. Türler eşleşmiyorsa, NumPy mümkünse Upcasting yapacaktır.
Upcasting: alt sınıftan oluşturulmuş bir nesneyi üst sınıftan oluşturulmuş bir nesneye çevirmek.
Downcasting ise üst sınıftan oluşturulmuş bir nesneyi alt sınıftan oluşturulmuş bir nesneye çevirme işine verilen addır.
Ortaya çıkan dizinin veri türünü açıkça ayarlamak istiyorsak,
dtypeanahtar kelimesini kullanabiliriz :
Son olarak, Python listelerinin aksine, NumPy dizileri çok boyutlu olabilir; bir liste listesi kullanarak çok boyutlu bir diziyi yaratabiliriz:
Eklenen listeler, elde edilen iki boyutlu dizinin satırları olarak değerlendirilir.
Sıfırdan Diziler Yaratmak
Özellikle daha büyük diziler için, NumPy’de yerleşik komutları kullanarak sıfırdan diziler oluşturmak daha verimlidir. İşte birkaç örnek:
Daha fazlası için: https://numpy.org/
Kaynak: Bu yazı, Jake VanderPlas’ın Python Veri Bilimi El Kitabından çevirilmiştir.
Berkay Akbulut