Büyük Verileri Okuma Yöntemleri

Kerim Caner TÜMKAYA
Data Runner
Published in
6 min readMay 18, 2020
Photo by Markus Spiske on Unsplash

Merhabalar, ben Kerim Caner Tümkaya. Yaklaşık 5 yıldır veri madenciliği ve veri bilimi alanında çalışıyorum. Bu benim ilk yazım :) Yazılarımda daha çok sektörde karşılaştığım sorunlara dair, bulduğum pratik çözümleri anlatmaya çalışacağım. Hadi başlayalım.

Bugün size Python Pandas kütüphanesi ile büyük verileri okuma yöntemlerinden bahsetmek istiyorum. Pandas Kütüphanesi Python ile Veri Bilimi projelerinde yer alan kişilerin en çok kullandığı kütüphanelerden birisidir. Veriyi bir çok farklı kaynaktan okumayı, veri üstünde bir çok manüplasyonu yapabilmeyi sağlar. Veriden modele giden yolda veriyi modele hazırlamak amacı ile kullanılan bir numaralı kütüphanedir. Ancak Pandas memory-based çalışır. Bu da veriyi okuduğunuzda verinin boyutunun size problem çıkarmasına neden olmaktadır. Bazı zamanlarda ise Pandas ile veriyi kolayca okuyabilseniz de ileride yapacağınız işlemlerde verinin boyutu sizi zorlamaya başlayabilir. Ancak bunlar için yapabileceğiniz bazı işlemler vardır. Şimdi adım adım onları inceleyelim;

Başlamadan önce işlemleri yaparken üstünde çalışacağım veriyi kısaca tanıtayım. Boyutu biraz da büyük olsun diye Kaggle içerisinde yer alan, InstaCart Basket Analysis yarışmasındaki veri setini kullanıyor olacağım. Kullandığım dosya ise bu veri setinin içinde yer alan “order_products__prior.csv” dosyası. Veriye buradan ulaşabilirsiniz.

Veriyi doğrudan okuyarak bir ön inceleme yapalım;

Verinin tamamını okumayı başardık, yaklaşık 16 sn sürdü.

Gördüğünüz gibi 4 sütunluk bir verimiz var. Peki bu veri ne kadar büyük? Şimdi de bunlara bakalım.

Verimizde 4 sütun var ancak 32 milyona yakın satırımız var. Verimizi büyüten etken de bu. Peki ne kadar yer kaplıyor bu veri?

Neredeyse 1 GB’lık bir yere sahip. Bu da bir sonraki işlemimizde bu boyutun başımızı ağrıtabileceği anlamına geliyor. Olası bir join işleminde MemoryError almanız çok muhtemel. Peki ne yapabiliriz? Gördüğünüz gibi verimizin kolonlarının tipi int64. int64 19 basamaklı sayıları tutabilen bir tip. Oysa bizim en büyük sayılarımızın yer aldığı kolonumuz olan “product_id” kolonumuz maksimum 5 haneli. int64 tipi bizim için fazla anlamına geliyor bu. İlk yapabileceğimiz işlem bu tipi değiştirerek küçültmek bu işlemlere downcasting deniliyor. Ve bu işlemler sadece numerik değerler üstünde yapılabiliyor. Peki nasıl, bunun iki farklı yöntemi var;

1 — Veri tipini veriyi okurken değiştirmek

2 — Veri tipini veriyi okuduktan sonra değiştirmek

Veri Tipini Veriyi Okurken Değiştirmek

Bu yöntemde Pandas’ın read fonksiyonlarının içinde bulunan dtypes parametresini kullanmamız gerekiyor. Bu işlem bize veriyi okuduğumuz anda boyut küçültmeyi sağlıyor. Ancak bir dezavantajı var. Veride yer alan kolonları bilmemiz gerekiyor. Çünkü dtypes parametre olarak bir dictionary alıyor. Ne demek istiyorum bir örnek üstünden ilerleyelim.

Yukarıda kolon adlarını ve o kolonların hangi tipte ele alınmasını istediğimizi belirten bir dictionary oluşturduk. Şimdi bunu read_csv içinde kullanıp boyutu görelim.

Gördüğünüz gibi bu işlem bize zaman kaybettirmedi yaklaşık 6 sn kadar daha hızlı da çalıştı. Peki verimizin kapladığı yerde şimdiki durum ne oldu? Bakalım.

Verinin boyutu neredeyse 8'de 1 azaldı. Bu veriyi joinlemek artık çok daha kolay :)

Peki diyelim ki verimizde çok fazla kolon var ama biz yine de okurken bu işlemi yapmak istiyoruz. Yani dictionary’i kod ile oluşturmak istiyoruz. Bunu nasıl yapabiliriz? Burada birçok alternatif yöntem daha çıkarılabilir. Aklınıza gelen bir alternatif yöntemi yorum olarak da bırakabilirsiniz ve üzerine konuşabiliriz. Benim yöntemim ise şöyle;

İlk olarak verinin tamamını okumak yerine nrows değişkenini kullanarak bir kısmını okuyalım. Böylece hem memory’de fazla yer kaplamasın hem de biz kolon adları ve onların tipleri hakkında bilgi edinebilelim.

Ardından ise dictionary’i oluşturalım.

Evet tipleri ve kolonları içeren bir dictionary elde ettik. Şimdi de bu tipleri küçültecek şekilde düzenleyelim dictionary’mizi.

Dictionary’nin son hali

Artık hazırız. Şimdi yeniden read_csv yapabiliriz. Ancak bu işlemde belirtmem gereken bir nokta da eğer verinizde ciddi bir outlier varsa bu yöntemde bir risk olabileceği. Riskten kastım nedir? Mesela siz ilk 100 satırı alarak dictionary oluşturdunuz. Ve ilk yüz satırda gelen veriler ışığında baktığınızda da verinizin int8 olması yeterli görülebilir. Ancak geri kalan kısımlarda int8'e sığmayacak bir değer var ise hata alırsınız. Bu hata işleyişinizi çok etkilemeyebilir ancak buna dair kontroller koymakta da yarar var.

Veri Tipini Veriyi Okuduktan Sonra Değiştirmek

Elimizdeki veri gibi bir veriniz olduğunu düşünelim. Yani verinin tamamını okuyabiliyorsunuz, ama kapladığı yer ilerleyen işlemlerde başınıza dert açabilir. Bu durumda veriyi okuduktan sonra tipleri küçültmeyi de düşünebilirsiniz. Bu işlem aynı zamanda yukarıda anlatmaya çalıştığım çok kolonu olan ve içinde ciddi aykırı değerler barındırabileceğine inandığınız veriler için daha güvenlidir.

Bunun için genellikle elinizin altında bir fonksiyon bulundurmanızı öneririm. Aşağıda buna dair benim kullandığım iki ayrı fonksiyonu anlatacağım. Ve o fonksiyonlar için iki ayrı referans bırakacağım. Bu konuda sizin de düşünceleriniz ve/veya eklemek istedikleriniz var ise, konuşabiliriz.

Kullandığım fonksiyon yukarıda yer almakta. Bu fonksiyonun avantajı, sizi int64'ten int16'ya mı int32'ye mi dönüştürmem lazım şeklinde düşünmekten kurtarması. Diğer avantajı ise integer değerleri signed integer olarak değil unsigned integer olarak küçültmesi. Bu da verinin kapladığı yeri daha büyük oranda küçültmenizi sağlıyor. Fonksiyon içinde string tipli değerleriniz olduğu gibi korunuyor. Daha önce de bahsettiğim gibi bu işlemleri sadece numerik değerler üstünden yapabiliyoruz. Ben bu fonksiyonu yazarken buradan faydalandım. Burada int8 int16 gibi tiplerin, unsigned ve signed integer tiplerin farklarını da bulabilirsiniz.

Peki bu fonksiyon bize ne kadar yer kazandırıyor?

Bir diğer fonksiyon yazma şekli de tüm veriyi okuduktan sonra, kolonlardaki maksimum ve minimum değerlere göre tip seçimi yapmak. Ben bu yöntemi pek kullanmıyorum ancak kullanmak isteyen olursa diye bir örnek fonksiyonu açıklayacağım.

Yukarıdaki fonksiyonu bu linkten örnek olarak aldım. Bu da downcasting yapmanın bir başka yolu. İlk yazılan fonksiyona göre daha hızlı çalıştığını fark etmiştim. Ancak ilk fonksiyonun küçültme oranı daha yüksek. Hız olarak ise fonksiyondaki concat kısımları hızın daha az olmasındaki etken. Onun dışında bu fonksiyonun yaptığı ile ilki aynı. Bu fonksiyon downcasting’in temel mantığını anlama adına kıymetli.

Büyük bir veriyi pandas ile efektif bir şekilde downcasting yapmanın yollarını anlatmış oldum. Fonksiyonlar üstünden ilerlemek bir küçültme oranımızı bir miktar daha azaltıyor. Ancak yine de oldukça işlevsel. Ancak bazı durumlarda bu yöntemler de işe yaramayabilir. Bu durumda Python üstünde bir başka veri okuma alternatifimiz olan Dask devreye girebilir. Bir sonraki yazımda da onu inceliyor olacağız.

İyi, güzel ve sağlıklı günler dilerim.

--

--