9.Hafta Scikit-Learn İle Veri Analitiğine Devam

Sonuçları değerlendirmek ve yorumlamak

scikit-learn modellerin sonuçlarını değerlendirmek ve yorumlamak için de çeşitli araçlar sunuyor. Sonuçları değerlendirmek için isabetlilik (accuracy) ve eğri altı alan (area under curve) değerlerini kullanacağız. metrics modülünün altında farklı yöntemleri (sınıflandırma, regresyon, kümeleme) değerlendirmek için araçlar da var.

In [8]:
#Sonuçları değerlendirmek için aşağıdaki fonksiyonları kullanacağız.
from sklearn.metrics import roc_auc_score, accuracy_score
#İsabetlilik değeri için etiketlere ihtiyacımız var.
print('Karar ağacı isabetlilik değeri: ' + str(accuracy_score(y_pred_dt, y_test)))
print('Rastgele orman isabetlilik değeri: ' + str(accuracy_score(y_pred_rf, y_test)))

#Eğri altı alan değeri için etiketlerin olasılıklarına ihtiyacımız var.
#Bu amaçla etiketlerin 1 değerinde olma yüzdelerini kullanacağız.
print('Karar ağacı eğri altı alan değeri: ' + str(roc_auc_score(y_test, y_pred_proba_dt[:,1])))
print('Rastgele orman eğri altı alan değeri: ' + str(roc_auc_score(y_test, y_pred_proba_rf[:,1])))
Karar ağacı isabetlilik değeri: 0.927374301676
Rastgele orman isabetlilik değeri: 0.960893854749
Karar ağacı eğri altı alan değeri: 0.928723138431
Rastgele orman eğri altı alan değeri: 0.997876061969

İsabetlilik değeri ve eğri altı değeri de rastgele orman yönteminde daha yüksek çıktı.

3 ve 8 rakamlarını ayırmamızı sağlayan öznitelikler (piksel değerleri) hangileri? Şimdi de features_importances_ özelliğini kullanarak modellerin önemli bulduğu piksellere bakalım.

In [9]:
features_dt = dt.feature_importances_
features_rf = rf.feature_importances_

features_dt = np.reshape(features_dt, (8,8))
features_rf = np.reshape(features_rf, (8,8))


plt.figure(figsize=(3,3))
plt.imshow(features_dt)
plt.title('Karar Ağacı')
plt.colorbar()
plt.show()


plt.figure(figsize=(3,3))
plt.imshow(features_rf)
plt.title('Rastgele Orman')
plt.colorbar()
plt.show()

Önemli olan öznitelikler sarı ve açık mavi, önemsiz olanlarsa koyu mavi ile gösteriliyor. Karar ağaçları daha çok 3 piksele bakarken, rastgele orman yöntemi daha fazla piksele bakarak karar veriyor. İki yöntem de ağırlıklı olarak resmin sol tarafına bakıyor, yani resimlerin sol tarafı 3 ve 8 rakamlarını ayırmak önemli olan pikselleri içeriyor.

Diğer Modüller

Bu yazıda sınıflandırma algoritmalarına bakmış olsak da scikit-learn altında başka modüller de var. Bunlardan sıklıkla kullanılanları aşağıda bulabilirsiniz:

  • cluster: Başta k-ortalamalar algoritması olmak üzere kümeleme yöntemlerini içeriyor.
  • ensemble: Adaboost, gradient boosting ve rastgele orman gibi grup halinde (ensemble) tahmin yapan yöntemleri bu modül altında yer alıyor.
  • feature_selection: Öznitelik seçme/azaltma algoritmalarını içeriyor.
  • linear_model: Başta doğrusal regresyon ve lojistik regresyon olmak üzere doğrusal yöntemleri içeriyor. Bu modül altında genelde regresyon yöntemleri bulunuyor.
  • metrics: Regresyon, sınıflandırma ve kümeleme problemlerinde elde ettiğiniz sonuçları değerlendirmek için kullanabileceğiniz araçları kapsıyor.
  • model_selection: Çapraz doğrulama (cross-validation) ve veri kümesini bölmek için kullanabileceğiniz bir modül.
  • neighbors: Gözlemlerin birbirine yakınlığı üzerinden sınıflandırma ve regresyon uygulayan yöntemlerden (k en yakın komşu yöntemi gibi) oluşuyor.
  • neural_network: Yapay sinir ağları üzerinden denemeler yapabileceğiniz bir modül. Ciddi bir çalışma gerçekleştirmek için başka paketlere ihtiyaç duyabilirsiniz.
  • preprocessing: Veri üzerinde ölçeklendirme, eksik değerleri doldurma ve kategorik değişkenleri ikili değerlere çevirmek gibi işlemleri preprocessing ile yapabilirsiniz.
  • svm: Destek vektör makineleri modülü. Sınıflandırma, regresyon ve aykırı gözlem bulmak için kullanılabilen algoritmalardan oluşuyor.
  • tree: Karar ağaçları temelli yöntemleri içeriyor.

8.Hafta Scikit-Learn İle Veri Analitiğine Giriş

Veri bilimine ilgi duyuyorsunuz ancak nereden başlayacağınız konusunda kafanız karışık mı? Python ekosistemi hakkında bilginiz var. Jupyter Notebook ile aranız fena değil. Sırada elinizi kirletmek var. Bunu yapmanın en kolay yollarından biri scikit-learn kütüphanesini kullanmak.

scikit-learn yapay öğrenme alanında en yaygın olarak kullanılan kütüphanelerden biri. Doğrusal regresyon, lojistik regresyon, karar ağaçları, rastgele orman gibi birçok temel yöntemi içeren bu kütüphane, Anaconda ile beraber geliyor. Anaconda kullanmayanlar web sitesinden kütüphaneyi nasıl yükleyeceklerini öğrenebilirler.

scikit-learn paketinin bu kadar popüler olmasının birkaç sebebi var. Bunlardan ilki ihtiyaç duyacağınız temel yöntemlerin büyük bir kısmını içermesi. İkinci olarak, scikit-learn sayesinde veri analitiği uygulamalarını baştan sona yürütmenizin mümkün olmasını sayabiliriz. Verideki eksik değerleri doldurmak, öznitelik seçmek, çapraz doğrulama yapmak, sonuçları değerlendirmek için ayrı ayrı modüller sayesinde başka bir pakete ihtiyacınız kalmıyor. scikit-learn paketinin en güzel yanı basit bir API’a sahip olması sayesinde uygulayacağınız farklı yöntemler için farklı sözdizimleri öğrenmenizin önüne geçmesi. Bu sayede veri analitiğine yeni başlayanlar hızla ellerini kirletebiliyorlar. fit/predict ya da fit/transform fonksiyonları sayesinde kümeleme, regresyon, karar ağaçları gibi yöntemleri uygulamak, eksik değerleri doldurmak, veriyi ölçeklendirmek gibi farklı adımlarda benzer fonksiyonlar kullanmak işinizi oldukça kolaylaştırıyor. API basit olmasının yanında çok iyi bir dokümantasyona sahip.

lightgbmtensorflow gibi kütüphaneler performans açısından ileride olsa da scikit-learnbaşlangıç seviyesindekiler için benim tavsiye edeceğim ilk kütüphane. Veri Defteri’nde scikit-learn paketinin API’ını bir örnek üzerinden anlatıp, temel modüllerden bahsedeceğiz. Bu amaçla yine scikit-learn altındaki veri kümelerini kullanacağız.

Örneğimiz digits veri kümesi üzerinden bir sınıflandırma problemi olacak. digits veri kümesi elle yazılmış rakamların 8*8 büyüklüğündeki resimlerinin piksel (8*8 = 64) değerlerinden oluşuyor. Amacımız veri kümesindeki 3 ve 8 rakamlarını birbirinden ayırmak. Kaan digits veri kümesinden bir yazısında bahsetmişti. Kullanacağımız modülleri, veri kümesini yükleyelim ve öğrenme ve sınama için ikiye bölelim.

In [1]:
#Rakamlar veri kümesini yüklüyoruz.
from sklearn.datasets import load_digits
#numpy paketini yüklüyoruz.
import numpy as np
#Veri kümesini ikiye bölmek için kullanıyoruz.
from sklearn.model_selection import train_test_split
#Resimleri incelemek için matplotlib kullanıyoruz.
%matplotlib inline
import matplotlib.pyplot as plt

#Veri kümesini etiket değerleriyle birlikte yükleyelim.
X,y = load_digits(return_X_y=True)
print('Verinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X)))
print('Etiketlerin boyutları (Gözlem) = ' + str(np.shape(y)))
Verinin boyutları (Gözlem, öznitelik) = (1797, 64)
Etiketlerin boyutları (Gözlem) = (1797,)

Veri kümesi 64 öznitelik (bunlar piksellerin değerlerine denk geliyor) ve 1797 gözlemden oluşuyor. Veri kümesinin ilk rakamını inceleyerek başlayalım. Rakamı çizdirmek için (1,64) olan boyutu (8,8) şeklinde değiştirmemiz gerekiyor. Bu amaçla da numpy altında reshape fonksiyonunu kullanacağız.

In [2]:
rakam1 = X[0]
rakam1 = np.reshape(rakam1, (8,8))

plt.figure(figsize= (2,2))
plt.imshow(rakam1, cmap="gray_r")
plt.show()
etiket1 = y[0]
print('Etiket: ' + str(etiket1))
Etiket: 0

Gördüğümüz gibi ilk rakam 0. Veri kümesindeki 3 ve 8 rakamlarını ayırmak istiyoruz. Bu amaçla filtreleme kullanacağız. Eğer bir rakam beşe bölündüğünde kalan üç ise istediğimiz koşulları sağlıyor.

In [3]:
#3 ve 8 rakamlarını seçmek için filtreleme kullanacağız.
#Filtrelemeyi etiket değerlerine (y) bakarak yapacağız. 
#Etiket değeri beşe bölündüğünde kalan üç ise bu gözlemleri veri kümesinde bırakıyoruz.
X= X[y%5 == 3]
y= y[y%5 == 3]

#Son olarak etiketleri 0 ve 1 değerlerine çevirelim.
#Rakam 3 ise etiket 0, 8 ise 1 olacak.
y = (y==8)*1
print('Verinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X)))
print('Etiketlerin boyutları (Gözlem) = ' + str(np.shape(y)))
Verinin boyutları (Gözlem, öznitelik) = (357, 64)
Etiketlerin boyutları (Gözlem) = (357,)

Öğrenen modellerin başarısını sınamak için veri kümesini öğrenme (train) ve sınama (test) olarak ikiye bölelim. Bu da scikit-learn altında yapılabilecek bir işlem. Burada dikkat etmemiz gereken, veri kümesini bölerken etiketlerin yüzdelerini korumak. Bu sayede veri kümesinin sadece bir rakamdan oluşması gibi durumların önüne geçmeyi hedefliyoruz. stratify argümanı ile veri kümesini bölerken etiket değerlerini de hesaba katıyoruz.

In [4]:
#Stratify değeri veri kümesinin etiket yüzdelerini korumak için kullanılıyor.
#Öğrenme veri kümesini küçük tutarak sonuçların çok iyi olmasını engelliyoruz.
#random_state değeri sonuçların her seferinde aynı çıkmasını sağlamak için kullanılıyor.
X_train, X_test, y_train, y_test = train_test_split(X,y, train_size = 0.5, test_size = 0.5, random_state = 0, stratify = y)

print('Öğrenme verisinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X_train)))
print('Sınama verisinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X_test)))
Öğrenme verisinin boyutları (Gözlem, öznitelik) = (178, 64)
Sınama verisinin boyutları (Gözlem, öznitelik) = (179, 64)

Veri kümesini ikiye böldük. Şimdi sınıflandırma için karar ağacı ve rastgele orman yöntemlerini kullanıp karşılaştıracağız. scikit-learn API’ının üç adımlık basit bir kullanımı var. Şimdi bu adımları inceleyelim.

Kullanacağımız sınıfa ait bir örnek oluşturma

Örnek olarak bir karar ağacı oluşturmak ya da eksik değerleri ortalama değerle doldurmak istiyorsunuz. Bu amaçla gerekli sınıflara (class) ait örnekleri istediğiniz parametrelerle oluşturmanız gerekiyor..

dt adında bir karar ağacı oluşturmak için DecisionTreeClassifier sınıfını kullanıyoruz:

dt = DecisionTreeClassifier()

Eksik değerleri ortalama değerle değiştirmek için ise Imputer sınıfını kullanacağız. NaN şeklinde olan eksik değerleri ortalama (mean) değerle değiştirmek istersek bunu kullanacağımız argümanlarla belirtmemiz gerekiyor.

mean_imputer = Imputer(missing_values = 'NaN', strategy = 'mean')

Aşağıda dt adında bir karar ağacı ve rf adında bir rastgele orman örneği tanımlıyoruz.

In [5]:
#Karar ağaçları
from sklearn.tree import DecisionTreeClassifier
#Rastgele orman
from sklearn.ensemble import RandomForestClassifier

#Karar ağacı modelini oluşturalım. 
#random_state değeri sayesinde sonuçların rassal olarak değişmemesini sağlıyoruz.
dt = DecisionTreeClassifier(random_state = 0)

#Rastgele orman modelini oluşturalım.
rf = RandomForestClassifier(random_state = 0)

Oluşturduğumuz örneğin öğrenmesini sağlama (fit)

Bir önceki aşamada oluşturduğumuz örneğin veri üzerinde öğrenmesi fit fonksiyonuyla yapılıyor. Örneğin bir karar ağacını öznitelik ve etiketleri kullanarak eğitmek için fitfonksiyonunu aşağıdaki gibi kullanabiliriz:

dt.fit(X_train, y_train)

Bu sayede öğrenme verisi üzerinden bir karar ağacı modeli oluşturulur.

Eksik değerleri doldurmak için de fit fonksiyonunu kullanacağız. Ancak burada fit fonksiyonu sadece yapacağımız işlemi tanımlıyor. Aşağıdaki satırda X_train matrisindeki eksik değer içeren sütunlar için ortalama değer hesaplanıyor.

mean_imputer.fit(X_train)

Şimdi yukarıda oluşturduğumuz karar ağacı ve rastgele orman modellerini eğitelim.

In [6]:
#Modellerin öğrenmesini sağlayalım.
dt.fit(X_train,y_train)
rf.fit(X_train,y_train)
Out[6]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

Sonuçları elde etmek (predict/predict_proba ve transform)

Oluşturduğunuz modelleri eğittikten sonra sonuçları elde etmek için kullanabileceğiniz iki farklı fonksiyon tipi var.

  • predict: Regresyon, sınıflandırma, kümeleme gibi yöntemler kullanarak yapacağınız çalışmalarda tahmin edilen etiket bilgisini predict fonksiyonuyla elde edebilirsiniz. Sınıflandırma problemlerinde gözlemlerin sınıflara ait olma olasılıklarını elde etmek istiyorsanız predict_proba fonksiyonunu kullanmanız gerekiyor.

Yukarıda oluşturduğumuz karar ağacı için etiketleri elde etmek için aşağıdaki satıra ihtiyacımız var:

y_pred = dt.predict(X_test)

Eğer etiketleri değil de olasılıkları öğrenmek istiyorsak predict_proba fonksiyonunu kullanmamız gerekiyor. Sonuçlar her etikete ait olma yüzdesini içeriyor.

y_pred_proba = dt.predict_proba(X_test)

  • transform: Veriyle ilgili yapacağımız dönüştürme işlemlerinde ise transform fonksiyonunu kullanacağız. Dönüştürme işlemleri eksik veriyi doldurma, veriyi ölçeklendirme gibi alanlarda karşımıza çıkıyor. Aynı zamanda bir matrisi çarpanlarına ayırmak gibi işlemler için de transform fonksiyonu kullanılıyor.

Eksik değerleri doldurmak için aşağıdaki satırı kullanabiliriz:

X_test = mean_imputer.transform(X_test)

Şimdi kullandığımız iki modeli sınama veri kümesinde kullanarak etiketleri ve gözlemlerin etiketlere ait olma olasılıklarını hesaplayalım.

In [7]:
#Sınama verisinin etiketlerini elde edelim.
y_pred_dt = dt.predict(X_test)
#Sınama veri kümesinin sınıflara ait olma olasılıklarını alalım.
y_pred_proba_dt = dt.predict_proba(X_test)

#Aynı adımları rastgele orman yöntemi için tekrarlayalım.
y_pred_rf = rf.predict(X_test)
y_pred_proba_rf = rf.predict_proba(X_test)

Burada dikkat etmemiz gereken bir nokta fit işlemlerini öğrenme, predict ve transformişlemlerini ise sınama verisi üzerinden yapmak. Yapacağımız çalışmalardaki amacımız öğrenme veri kümesiyle yakaladığımız örüntüleri sınama verisi üzerinde denemek. Yani, sınama veri kümesinin sadece son aşamada kullanılması gerekiyor. Eksik değerleri doldurmak gibi konularda da öğrenme verisiyle elde ettiğimiz bilgileri (örnek olarak ortalamayı) sınama verisinde kullanıyoruz. Sınama veri kümesi için de fit fonksiyonunu kullanmak sıklıkla yapılan bir hata.

Aşağıdaki satırlarda öğrenme verisindeki sütunlar için ortalama değeri bulup eksik değerleri dolduruyoruz. Daha sonra da sınama verisindeki sütunlar için ortalama değerleri bulup eksik değerleri doldurmak için kullanıyoruz. Oysa ki yapmamız gereken sınama verisinde de öğrenme verisindeki ortalamaları kullanmak.

mean_imputer.fit(X_train)
X_train = mean_imputer.transform(X_train)
mean_imputer.fit(X_test)
X_test = mean_imputer.transform(X_test)

10.Hafta Derin Öğrenme Nedir?

İnsan beyni o kadar mükemmel bir yapıdadır ki bir şeyi öğrenmek için elinden gelen her şeyi yapar. Bilgiden gelen sinyalleri gerekli yerlere ulaştırır ve o bilginin özümsenmesini sağlar. Bu mükemmel beyin zamanla o kadar gelişir ki kendi yeteneklerini yapay, elektronik cihazlara öğretmeye başlar. Tekdüze bilgiler beyin tarafından kolay bir şekilde karşıya aktarılabilir. Ama aktarılmasının çok daha zor olduğu bir kabiliyet vardır: Öğrenme.

Şu anda sayıları 100’ü çoktan aşmış olan programlama dilleri ile belirli bir seviyede işlemciye sahip cihazları programlayabiliyoruz. Bu cihazlar bizden aldıkları yönergeleri yine bizden aldıkları zaman dilimlerinde uyguluyorlar ve bunda oldukça da iyiler. Teknolojinin bu kadar ileri gitmesinde en büyük pay sahibi şüphesiz bu programlanabilme özelliğidir. Ama bu yetenek tabi ki bir insan beyninin yerine geçemiyor. Tekrarlardan, kontrol gruplarından, matematiksel işlemlerden oluşan yapıları çok kolay anlayabilip çözebilirken; mantık yürütülmesi gereken, kesin olmayan ifadelerde bakakalıyor. Hemen hemen herkesin bilim-kurgu filmlerinden aşina olduğu yapay zeka kavramı yine karşımızda. Ortada bir zekadan bahsediyorsak bunun öğrenme yeteneğinden yoksun olması beklenemezdi. Bir şekilde bu sisteme öğrenme yöntemlerini öğretmek gerekiyor. Burada da Deep Learning (Derin Öğrenme) kendini gösteriyor.

Yapay Sinir Ağları ve Derin Öğrenme

Deep Learning (Derin Öğrenme) aslında yepyeni bir kavram değil.İnsan beyninin çalışma şeklinden ilham alınarak geliştirilen yapay sinir ağları uzun süredir üzerinde çalışılan bir konu.Deep Learning bu yapay sinir ağlarının geliştirilmesiyle ortaya çıktı. Önceki yıllarda geliştrilmiş olan yapay sinir ağlarının belirgin özelliği bir veya iki katmandan oluşmasıydı.Bu yeni kavramların havada kalmasını önlemek için aşağıdaki modellemeye göz atmakta fayda var.

Burada gördüğümüz basit bir yapay sinir ağı.Ne kadar basit olsa da birçok ihtimalin görsel olarak ifade edilebildiğini gözden kaçırmamak gerek.Resimde “input layer” olarak geçen bölümü verinin alındığı yer olarak düşünebiliriz. “hidden layer” ise bu verinin işlendiği yer oluyor. “output layer” tahmin edeceğiniz üzere karar aşamasını temsil ediyor. İşte bu sinir ağının verinin miktarı, içteki karar verme kısımları ve sonuç sayısı açısından daha zengin hali Deep Learning olarak karşımıza çıkıyor. Aşağıdaki grafik grafik günümüzde veri miktarının artmasıyla beraber Derin öğrenmenin basit yapay sinir ağlarıyla oluşturulan öğrenme algoritmalarından nasıl daha iyi sonuç verdiğini ortaya koyuyor.

Why Deep Learning ? Slide by Andrew Ng,All rights reserved.

Deep Learning hakkında ülkemizde yapılan çalışmalar ne yazık ki istenilen düzeyde değil.Bunu konu hakkındaki Türkçe kaynakların azlığında da görebiliyoruz.

6.Hafta Makine Öğrenmesi Nedir

Son dönemde adını sıkça duyduğumuz Makine Öğrenmesi’ni mümkün olduğunca basit halde sizlere anlatmaya çalışacağım. Makine Öğrenmesi (Machine Learning), matematiksel ve istatistiksel yöntemler kullanarak mevcut verilerden çıkarımlar yapan, bu çıkarımlarla bilinmeyene dair tahminlerde bulunan yöntem paradigmasıdır. Makine öğrenmesine güncel hayatımızdan bazı örnekler: yüz tanıma, belge sınıflandırma, spam tespiti.

Bir benzetme yapacak olursak öğrenci konu çalışıp ders kitabındaki örnek çözümlü soruları çözer ve öğrenir. Ardından kitapta bulunmayan ama aynı bilgiye dayanan farklı bir test önüne konulur. Öğrenci cevapları bilmeden testi çözer. Sonra değerlendirmeye alınır, ne kadar başarılı olduğu görülür. Eğer ezberci bir öğrenciyse benzeri kitapta olmayan soruları muhtemelen yanlış yanıtlayacaktır. Eğer işin temelini anlayan bir öğrenciyse farklı tarzda soru gelse bile doğru çözebilecektir. Öğrenci test sonucunu ve nerelerde hata yaptığını inceler. “Hmm şu soruda şöyle bir genelleme yapmışım ama aslında iş bu kadar basit değilmiş”, “Hmm şu etkeni hesaba katmayı düşünemedim” gibi dersler çıkarır kendisine. Ardından derslerini almış bir gözle kitabını tekrar çalışır ve tekrar testi çözer. Yeterince iyi sonuç alana kadar hatalarını keşfedip konunun püf noktalarını öğrenmeye çalışır.

Makine öğrenmesi de bunun çok benzeridir. Süreç aynıdır. Öncelikle terminolojiden bahsedelim. Ardından en temel 2 öğrenme türünü tanıyalım ve örnek bir makine öğrenme sürecini anlayalım.

Terminoloji

  • Gözlemler (Observations): öğrenmek ya da değerlendirmek için kullanılan her bir veri parçası. Örn: her bir e-posta bir gözlemdir.
  • Özellikler (Features): Bir gözlemi temsil eden (genelde sayısal) verilerdir. Örn: e-posta’nın uzunluğu, tarihi, bazı kelimelerin varlığı.
  • Etiketler (Labels): Gözlemlere atfedilen kategoriler. Örn: spam, spam-değil.
  • Eğitim Verisi (Training Data): Algoritmanın öğrenmesi için sunulan gözlemler dizisi. Algoritma bu veriye bakarak çıkarımlarda bulunur, kafasında model kurar. Örn: çok sayıda spam/spam-değil diye etiketlenmiş e-posta gözlemi
  • Test Verisi (Test Data): Algoritmanın kafasında şekillendirdiği modelin ne kadar gerçeğe yakın olduğunu test etmek için kullanılan veri seti. Eğitim esnasında saklanır, eğitim bittikten sonra etiketsiz olarak algoritmaya verilerek algoritmanın (vermediğimiz etiketler hakkında) tahminlerde bulunması beklenir. Örn: spam olup olmadığı bilinen (ama gizlenen), eğitim verisindekilerden farklı çok sayıda e-posta gözlemi

İki Temel Öğrenme Türü

Gözetimli Öğrenme

Etiketlenmiş gözlemlerden öğrenme sürecidir. Etiketler, algoritmaya gözlemleri nasıl etiketlemesi gerektiğini öğretir. Örneğin içinde “para kazan” ifadesi geçiyorsa spam demelisin gibi yol göstermelerde bulunur.

Sınıflandırma (Classification): Her bir gözleme bir kategori/sınıf atması yapar: Örn: spam/spam değil. Sınıflar ayrıktır (sayı değildir) ve birbirlerine yakın/uzak olmaları gibi bir durum söz konusu değildir.

Regresyon (Regression): Her gözlem için öğrendiklerine bakarak reel bir değer tahmini yapar. Örn: “2011 model 40.000 km’de Mia Torento arabanın fiyatı 45.670 TL olmalıdır”.

Gözetimsiz Öğrenme

Etiketsiz gözlemlerden öğrenme sürecidir. Algoritmanın kendi kendine keşifler yapması, gözükmeyen örüntüleri keşfetmesi beklenir.

Kümeleme (Clustering): Gözlemleri homojen bölgelere ayırır. Örn: bir okuldaki öğrenci gruplarını tespit etmek.

Boyut Azaltımı (Dimensionality Reduction): Gözlemlerin mevcut özellik sayısını az ve öz hale indirir, bize en iyi öğrenme imkanı sunar.

Öğrenme Süreci

Peki nasıl öğreniyor bu algoritmalar?

Öncelikle ham veri (raw data) buluyoruz. Örn: Metin, görüntü, genetik verisi, sayısal ölçümler, sosyal ağlar, kullanıcı puanlamaları…

Regresyon tipi gözetimli öğrenme üzerinden örnek verelim. Elimizde hastaların sağlık verileri olsun. Her hasta için: yaş, cinsiyet, sigara içiyor mu, günde kaç sigara içiyor, şeker hastalığı var mı, daha önce kalp krizi geçirdi mi, kolestrolü kaç, nabzı kaç, şeker seviyesi kaç?

Ad AnneAdı DahaOnceKriz SigaraSayisi Kolestrol KrizGeçirdiMi
Mehmet Leyla 1 12 100 .. 1
Murat Ayşe 0 6 170 .. 1
Fahri Tuba 0 3 30 .. 0

Bu verilere bakarak hastaların 10 yıl içinde kalp krizi geçirme olasılığını tahmin edelim.

Özellik Çıkarımı (Feature Extraction)

Gözlemlerimizi en iyi temsil edecek özellikleri kullanmak etmek için ham veriden Özellik Çıkarımı (Feature Extraction) ve çıkarılan özellikler üzerinde Özellik Seçimi (Feature Selection) yapıyoruz. Bu süreçte alan bilgisi (domain knowledge) uygulamak gerekiyor. Yani bu işi tecrübesiz bir insana anlatacak olsaydık hangi özelliklere bak derdik? Bu özellikleri tanımlayıp hesaplamak gerekli. Örneğin kalp hastalığı tespitinde “AnneAdı” özelliğinin pek de işe yaramayacağını öngörebiliriz. En çok şüphelendiğimiz sigara sayısı, daha önce kalp krizi geçirdi mi? gibi özellikleri hesaba katmakta fayda var. Gereksiz kısımları temizlemeliyiz.

Model Oluşturma

Özellikler çıktıktan sonra bir öğrenme algoritması bu matris üzerinde çalışıyor. Sonucunda bir takım kurallar çıkarıyor. Örneğin basit bir algoritma az sayıda veriye bakarak bazı şöyle bir model ortaya koyabilirdi:

Kriz olasılığı = günlük sigara sayısı x 0.05 + kolestrol seviyesi x 0.004

Ancak gözlem sayısı arttıkça daha karmaşık yorumlar yapabiliyor.

Değerlendirme

Elimizde artık bir modelimiz var. Şimdi test verisiyle test etmeliyiz:

Ad AnneAdı DahaOnceKriz SigaraSayisi Kolestrol KrizGecirdiMi
Mert Beyza 1 10 80 .. 1
Davut Fatma 1 15 40 .. 1
Veysel Kadriye 0 5 15 .. 0

Elimizde etiketi (10 yıl içinde kalp krizi geçirdi / geçirmedi) gizlenmiş hasta gözlemlerini (test verisini) modele uygulayarak her birisi için bir olasılık çıkarıyoruz. Ardından olasılık 0.5’den büyükse kriz geçireceğini iddia ediyorum diyoruz. Modelin ürettiği bu tahminleri elimizdeki gerçek kriz bilgileriyle karşılaştırıp ne kadar başarılı bir tahmin yaptığını değerlendiriyoruz.

Ad AnneAdı DahaOnceKriz SigaraSayisi Kolestrol KrizGecirdiMi HesaplananOlasılık
Mert Beyza 1 10 80 .. 1 0.82
Davut Fatma 1 15 40 .. 1 0.91
Veysel Kadriye 0 5 15 .. 0 0.85

Eşik olarak 0.5 kullandığımızda bu test verisindeki herkesin kalp krizi geçirmesini bekliyoruz ama Veysel 10 yıl içinde geçirmemiş. Eğer eşiği 0.9 deseydik Veysel’in kriz geçirmeyeceğini bilecektik ama gerçekte kriz geçiren Mert’in kriz geçireceğini iddia edemeyecektik.

Değerlendirmede kullandığımız kıstaslar:

  • Accuracy (Doğruluk)doğru bildiğimiz / toplam gözlem. Bunu hem model tahminimiz için yapıyoruz, hem de baseline (dayanak) denilen basit tahmin için. Dayanak, eğitim verisindeki gözlemlerin yüzde kaçı kriz geçirmiş sorusuna verdiğimiz cevap oluyor. Yani hiçbir fikrimiz olmadığında öne sürebileceğimiz en iyi cevap. Model doğruluğu, dayanak doğruluğundan ne kadar iyiyse o kadar iyi.
  • Sensitivity (hassaslık), gerçekten kriz geçiren kimselerden yüzde kaçını “kriz geçirecek” diyerek bildik?
  • Specificity (belirginlik), kriz geçirmeyen kimselerden yüzde kaçını “kriz geçirmeyecek” diyerek bildik?

Model oluşturma yöntemine göre bu değerleri kullanarak daha karmaşık metrikler hesaplanıp yorumlanabiliyor. 0.5 olarak kullandığımız karar katsayısını 0.95 yaparak “iddiamdan ancak çok eminsem kriz geçirecek derim” diyebiliriz, bu da hassaslığı düşürür. Çünkü kimse kriz geçirmeyecek demiş oluruz. belirginliği artırır çünkü kriz geçirmeyecek insanları daha çok insanı bilmiş oluruz. Katsayıyı 0.3 yaparsak ise birçok kişiye potansiyel hasta muamelesi yapmış oluruz, durum tersine döner. Kalp krizi hayati bir olay olduğu için bütçe elverdiği ölçüde bu katsayıyı düşük tutmakta fayda var.

Bununla birlikte modelin karmaşıklığına göre tahmin sonuçları değişecektir. Eğer model çok basitse (az sayıda özelliğe bakarak karar veriyorsa) çok daha hızlı çalışacaktır. Eğer iyi genelleme yapabiliyorsa farklı veri kümelerinde iyi tahminler yapabilir. Ama az miktarda veriye bakarak genelleme yaptıysa bu genelleme farklı veri kümelerinde yanlış tahminlere yöneltecektir.

Bunu engellemek için modelin karmaşıklığını artırırsak bu sefer eğitim kümesini ezberleme durumu ortaya çıkar. Yani eğer hasta 53 yaşındaysa ve günde 9 sigara içip 45.9 kolestrole sahipse ve … .. kalp krizi geçirir gibi ezber kokan yanıtlar vermeye başlar. Bu modeli eğitim kümesinde test edecek olursak %100’e yaklaşan başarı gösterir. Ama 53 yaşında 9 sigara içen ve 50 kolestrole sahip birisi hakkında doğru yorum yapamaz. Çünkü ezberlediği bilgiler arasında bu gözlem yoktur.

Modelin karmaşıklığı iyi ayarlanmalıdır. Ne eğitim verisini ezberlemeli, ne de çok basit genellemeler yapmalıdır. Mümkün olduğunca (fazla değil) basit olmalıdır.

İyileştirme

Eğer modelin yeterince başarılı olmadığını düşünüyorsak nerelerde hata yaptığını inceleyip modelimize hangi özellikleri vermemz gerektiğini düşünmeliyiz. Bazı özellikleri çıkarmalı, bazı özellikleri eklemeli, yeniden bir model oluşturup tekrar değerlendirmeliyiz. Bu süreç tatmin olana kadar devam edebilir ama sonu yoktur.

Veri -> Temizleme -> Özellik çıkarımı -> Öğrenme Algoritması -> Model -> Değerlendirme -> İyileştirme -> Temizleme -> ...

Örneğin ilk modelimizin yeterli olmadığını gördüğümüzde “bir de daha önce kalp krizi geçirmiş mi” özelliğine bakalım deyip ayrı bir model oluşturup onu test edip daha başarılı olduğunu görebiliriz. Modelin performansı, sağlamlığı konusunda çeşitli metrikler mevcuttur.

Tahmin

Eğer modelimizin test kümesinde başarılı şekilde tahmin yürüttüğünü düşünüyorsak başka veriler üzerinde modeli çalıştırıp tahminler yapmaya, modelden faydalanmaya başlayabiliriz.

Sonuç olarak

Makine Öğrenmesi kimi zaman çok faydalı olabilmektedir ancak sihirli bir değnek de değildir, farklı algoritmalar, farklı özellikler, farklı veriler ile çok sayıda deneme yanılma girişimiyle model oluşturma sabrı gerektirir. Makine Öğrenmesi konusuda daha çok bilgi öğrenmek istiyorsanız Coursera, edX, Udacity gibi platformlardan faydalanabilirsiniz. Aldığım The Analytics Edge dersinden ben son derece memnun kaldım. Ayrıca 9. Veri Bilimi İstanbul buluşmasında gerçekleştirdiğim sunumu Youtube üzerinden izleyebilirsiniz:

7.Hafta Tahmin Ve Çıkarım (Makine öğrenmesi? Yapay Öğrenme?)

“Yapay Öğrenme” mi, yoksa “Makine Öğrenmesi” mi? Belki de “İstatiksel Öğrenme.” Açıkçası ben de bir türlü karar veremiyorum. Bir bilgisayar mühendisi kadar iddialı değilim; onun için ilk iki seçeneği kullanmak istemedim. İstatistik bilgim idare eder. Fakat doğruya doğru, mektepli istatistikçilerle aşık atamam. Öte yandan önümüzdeki güz döneminde, bizim üniversitede çoğunluğunu optimizasyon ve istatistikçilerin oluşturduğu bir gruba “Machine Learning” isimli bir yüksek lisans dersi vereceğim. Yani öyle ya da böyle, bu derse iyi hazırlanmam gerek. Kaçış yok. Onun için isme fazla takılmasam iyi olacak.

Çalışmaya başladım. Bir yandan da ders notları hazırlıyorum ki konuyu daha iyi anlayayım. Yüksek lisans dersi İngilizce olacak (Hollandaca da anlatabilirim ama pişman olurlar). İşin güzel tarafı, bu tür derslerde kullandığım sunum dosyalarında fazla yazı olmuyor. Ben de madem az metin var, o zaman neden Türkçe olmasın diye düşündüm. Bir yandan da dersleri videoya çekmeyi deneyeceğim. Bu şekilde hem Veri Defteri için farklı bir kaynağımız daha olur, hem de sizden gelen önerilerle notlarım iyileşir.

Aklımdaki konular şunlar:

  1. Giriş
    • Ne yapıyoruz?
    • Farklı veri tipleri
    • Bağlanım (regression) ve sınıflandırma (classification)
    • Güdümlü (supervised) ve güdümsüz (unsupervised) öğrenme
  2. Performans Ölçümü
    • Eğitim (training) ve test hataları
    • Aşırı uyum (overfitting)
    • Yanlılık (bias) – Varyans
    • Bayes sınıflandırıcısı (classifier) – K-En Yakın Komşu (KEYK)
  3. Doğrusal Bağlanım
    • Modelin kurulması
    • Katsayıların elde edilmesi
    • Kategorik değişkenlerin eklenmesi
    • KEYK ile karşılaştırma
  4. Düzenlileştirme (Regularization) 
    • Alt küme seçimi
    • Çıkıntı (ridge) bağlanımı ve Lasso
    • Boyut indirme (dimension reduction)
  5. Sınıflandırma ve Tekrar Örnekleme (Resampling)
    • Lojistik (logistic) Bağlanım
    • Doğrusal Ayrımsayıcı Çözümleme (Linear Discriminant Analysis)
    • Çapraz geçerlilik sınaması (cross validation) ve zorlama tekniği (bootstrap technique)
  6. Karar Ağaçları (Decison Trees)
    • Bağlanım ve sınıflandırma ağaçları
    • Rassal Ormanlar (Random Forests)
    • Torbalama (bagging) ve takviye (boosting)
  7. Gruplandırma (Clustering)
    • Ana Bileşenler Analizi (Principal Component Analysis)
    • K-Ortalamalar gruplandırma
    • Hiyerarşik gruplandırma
    • Spektral gruplandırma
  8. Destek Vektör Makineleri (Support Vector Machines)
    • Ayırıcı düzlemler (separating hyperplanes)
    • Destek vektör sınıflandırıcıları (classifiers)
    • Çoklu sınıf
  9. Yapay Sinir Ağları (Artificial Neural Networks)
    • Temel ağ yapısı
    • Etkinleştirme (activation) fonksiyonları
    • Geri yayılım (backpropagation)

Ta en baştan çok katı bir içeriği garanti etmem oldukça güç elbette. Eminim zaman içinde eklemeler ve çıkarmalar olacaktır. Ancak yine de yukarıdaki konular size bir fikir verir diye tahmin ediyorum. Bu arada içerikten de göreceğiniz üzere sık sık Türkçe teknik terimlere ihtiyacımız olacak. Çeviri için farklı kaynakları düşündüm. En sonunda TÜBA Türkçe Bilim Terimleri Sözlüğü‘nü esas almaya karar verdim.

Ders notlarımı hazırlarken mümkün mertebe bir kitaba bağlı kalmayı seviyorum. Bu sayede dersi takip edenlerin, derste işlemediğim veya iyi anlamadıkları konuları kendi başlarına çalışmaları mümkün oluyor. İstatiksel ya da yapay öğrenme konularında yazılmış çok iyi kitaplar var. Bir süre inceledikten sonra şu kitapta karar kıldım:

“An Introduction to Statistical Learning – with Applications in R,” G. James, D. Witten, T. Hastie, R. Tibshirani. Yedinci baskı, Springer, New York, 2013.

Kitabın teknik ayrıntıları atlayarak ilerlemesini çok sevdiğimi söyleyemem. Ancak aklımı çelen birkaç yanı var. Öncelikle kitabın dijital kopyasına, kullanılan veri kümelerine ve kodlara ücretsiz olarak erişilebiliyor. Ayrıca kitabın her bölümünün sonunda bilgisayar başında yapılması istenen uygulamalar verilmiş. Kitap R programlama dilini kullanmış ve tüm kodlar aynı sayfada mevcut. Ancak biraz arayınca Python kodlarını da kolayca bulabilirsiniz. Bir diğer sebep de bu kitabı hazırlayanlardan Hastie ve Tibshirani’nin yanlarına J. Friedman’ı alarak yazdıkları bir kitap daha olması. Doğrusu o kitap, benim bayağı beğendiğim bir kaynak. Teknik olarak kesinlikle daha fazla ayrıntıya giriyor. Eğer bu ders için seçtiğim kitaptan hoşlanmazsanız, o kitabı takip edebilirsiniz. Orada benim anlatacağım konular daha derinlemesine inceleniyor. Bu arada unutmadan ekleyeyim. Seçtiğim kitap Yapay Sinir Ağları konusuna girmiyor. O konu için birkaç kitaptan yararlanacağım. Zamanı gelince referansları veririm.

9.Hafta Scikit-Learn İle Veri Analitiğine Devam

Sonuçları değerlendirmek ve yorumlamak

scikit-learn modellerin sonuçlarını değerlendirmek ve yorumlamak için de çeşitli araçlar sunuyor. Sonuçları değerlendirmek için isabetlilik (accuracy) ve eğri altı alan (area under curve) değerlerini kullanacağız. metrics modülünün altında farklı yöntemleri (sınıflandırma, regresyon, kümeleme) değerlendirmek için araçlar da var.

In [8]:
#Sonuçları değerlendirmek için aşağıdaki fonksiyonları kullanacağız.
from sklearn.metrics import roc_auc_score, accuracy_score
#İsabetlilik değeri için etiketlere ihtiyacımız var.
print('Karar ağacı isabetlilik değeri: ' + str(accuracy_score(y_pred_dt, y_test)))
print('Rastgele orman isabetlilik değeri: ' + str(accuracy_score(y_pred_rf, y_test)))

#Eğri altı alan değeri için etiketlerin olasılıklarına ihtiyacımız var.
#Bu amaçla etiketlerin 1 değerinde olma yüzdelerini kullanacağız.
print('Karar ağacı eğri altı alan değeri: ' + str(roc_auc_score(y_test, y_pred_proba_dt[:,1])))
print('Rastgele orman eğri altı alan değeri: ' + str(roc_auc_score(y_test, y_pred_proba_rf[:,1])))
Karar ağacı isabetlilik değeri: 0.927374301676
Rastgele orman isabetlilik değeri: 0.960893854749
Karar ağacı eğri altı alan değeri: 0.928723138431
Rastgele orman eğri altı alan değeri: 0.997876061969

İsabetlilik değeri ve eğri altı değeri de rastgele orman yönteminde daha yüksek çıktı.

3 ve 8 rakamlarını ayırmamızı sağlayan öznitelikler (piksel değerleri) hangileri? Şimdi de features_importances_ özelliğini kullanarak modellerin önemli bulduğu piksellere bakalım.

In [9]:
features_dt = dt.feature_importances_
features_rf = rf.feature_importances_

features_dt = np.reshape(features_dt, (8,8))
features_rf = np.reshape(features_rf, (8,8))


plt.figure(figsize=(3,3))
plt.imshow(features_dt)
plt.title('Karar Ağacı')
plt.colorbar()
plt.show()


plt.figure(figsize=(3,3))
plt.imshow(features_rf)
plt.title('Rastgele Orman')
plt.colorbar()
plt.show()

Önemli olan öznitelikler sarı ve açık mavi, önemsiz olanlarsa koyu mavi ile gösteriliyor. Karar ağaçları daha çok 3 piksele bakarken, rastgele orman yöntemi daha fazla piksele bakarak karar veriyor. İki yöntem de ağırlıklı olarak resmin sol tarafına bakıyor, yani resimlerin sol tarafı 3 ve 8 rakamlarını ayırmak önemli olan pikselleri içeriyor.

Diğer Modüller

Bu yazıda sınıflandırma algoritmalarına bakmış olsak da scikit-learn altında başka modüller de var. Bunlardan sıklıkla kullanılanları aşağıda bulabilirsiniz:

  • cluster: Başta k-ortalamalar algoritması olmak üzere kümeleme yöntemlerini içeriyor.
  • ensemble: Adaboost, gradient boosting ve rastgele orman gibi grup halinde (ensemble) tahmin yapan yöntemleri bu modül altında yer alıyor.
  • feature_selection: Öznitelik seçme/azaltma algoritmalarını içeriyor.
  • linear_model: Başta doğrusal regresyon ve lojistik regresyon olmak üzere doğrusal yöntemleri içeriyor. Bu modül altında genelde regresyon yöntemleri bulunuyor.
  • metrics: Regresyon, sınıflandırma ve kümeleme problemlerinde elde ettiğiniz sonuçları değerlendirmek için kullanabileceğiniz araçları kapsıyor.
  • model_selection: Çapraz doğrulama (cross-validation) ve veri kümesini bölmek için kullanabileceğiniz bir modül.
  • neighbors: Gözlemlerin birbirine yakınlığı üzerinden sınıflandırma ve regresyon uygulayan yöntemlerden (k en yakın komşu yöntemi gibi) oluşuyor.
  • neural_network: Yapay sinir ağları üzerinden denemeler yapabileceğiniz bir modül. Ciddi bir çalışma gerçekleştirmek için başka paketlere ihtiyaç duyabilirsiniz.
  • preprocessing: Veri üzerinde ölçeklendirme, eksik değerleri doldurma ve kategorik değişkenleri ikili değerlere çevirmek gibi işlemleri preprocessing ile yapabilirsiniz.
  • svm: Destek vektör makineleri modülü. Sınıflandırma, regresyon ve aykırı gözlem bulmak için kullanılabilen algoritmalardan oluşuyor.
  • tree: Karar ağaçları temelli yöntemleri içeriyor.

8.Hafta Scikit-Learn İle Veri Analitiğine Giriş

Veri bilimine ilgi duyuyorsunuz ancak nereden başlayacağınız konusunda kafanız karışık mı? Python ekosistemi hakkında bilginiz var. Jupyter Notebook ile aranız fena değil. Sırada elinizi kirletmek var. Bunu yapmanın en kolay yollarından biri scikit-learn kütüphanesini kullanmak.

scikit-learn yapay öğrenme alanında en yaygın olarak kullanılan kütüphanelerden biri. Doğrusal regresyon, lojistik regresyon, karar ağaçları, rastgele orman gibi birçok temel yöntemi içeren bu kütüphane, Anaconda ile beraber geliyor. Anaconda kullanmayanlar web sitesinden kütüphaneyi nasıl yükleyeceklerini öğrenebilirler.

scikit-learn paketinin bu kadar popüler olmasının birkaç sebebi var. Bunlardan ilki ihtiyaç duyacağınız temel yöntemlerin büyük bir kısmını içermesi. İkinci olarak, scikit-learn sayesinde veri analitiği uygulamalarını baştan sona yürütmenizin mümkün olmasını sayabiliriz. Verideki eksik değerleri doldurmak, öznitelik seçmek, çapraz doğrulama yapmak, sonuçları değerlendirmek için ayrı ayrı modüller sayesinde başka bir pakete ihtiyacınız kalmıyor. scikit-learn paketinin en güzel yanı basit bir API’a sahip olması sayesinde uygulayacağınız farklı yöntemler için farklı sözdizimleri öğrenmenizin önüne geçmesi. Bu sayede veri analitiğine yeni başlayanlar hızla ellerini kirletebiliyorlar. fit/predict ya da fit/transform fonksiyonları sayesinde kümeleme, regresyon, karar ağaçları gibi yöntemleri uygulamak, eksik değerleri doldurmak, veriyi ölçeklendirmek gibi farklı adımlarda benzer fonksiyonlar kullanmak işinizi oldukça kolaylaştırıyor. API basit olmasının yanında çok iyi bir dokümantasyona sahip.

lightgbmtensorflow gibi kütüphaneler performans açısından ileride olsa da scikit-learnbaşlangıç seviyesindekiler için benim tavsiye edeceğim ilk kütüphane. Veri Defteri’nde scikit-learn paketinin API’ını bir örnek üzerinden anlatıp, temel modüllerden bahsedeceğiz. Bu amaçla yine scikit-learn altındaki veri kümelerini kullanacağız.

Örneğimiz digits veri kümesi üzerinden bir sınıflandırma problemi olacak. digits veri kümesi elle yazılmış rakamların 8*8 büyüklüğündeki resimlerinin piksel (8*8 = 64) değerlerinden oluşuyor. Amacımız veri kümesindeki 3 ve 8 rakamlarını birbirinden ayırmak. Kaan digits veri kümesinden bir yazısında bahsetmişti. Kullanacağımız modülleri, veri kümesini yükleyelim ve öğrenme ve sınama için ikiye bölelim.

In [1]:
#Rakamlar veri kümesini yüklüyoruz.
from sklearn.datasets import load_digits
#numpy paketini yüklüyoruz.
import numpy as np
#Veri kümesini ikiye bölmek için kullanıyoruz.
from sklearn.model_selection import train_test_split
#Resimleri incelemek için matplotlib kullanıyoruz.
%matplotlib inline
import matplotlib.pyplot as plt

#Veri kümesini etiket değerleriyle birlikte yükleyelim.
X,y = load_digits(return_X_y=True)
print('Verinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X)))
print('Etiketlerin boyutları (Gözlem) = ' + str(np.shape(y)))
Verinin boyutları (Gözlem, öznitelik) = (1797, 64)
Etiketlerin boyutları (Gözlem) = (1797,)

Veri kümesi 64 öznitelik (bunlar piksellerin değerlerine denk geliyor) ve 1797 gözlemden oluşuyor. Veri kümesinin ilk rakamını inceleyerek başlayalım. Rakamı çizdirmek için (1,64) olan boyutu (8,8) şeklinde değiştirmemiz gerekiyor. Bu amaçla da numpy altında reshape fonksiyonunu kullanacağız.

In [2]:
rakam1 = X[0]
rakam1 = np.reshape(rakam1, (8,8))

plt.figure(figsize= (2,2))
plt.imshow(rakam1, cmap="gray_r")
plt.show()
etiket1 = y[0]
print('Etiket: ' + str(etiket1))
Etiket: 0

Gördüğümüz gibi ilk rakam 0. Veri kümesindeki 3 ve 8 rakamlarını ayırmak istiyoruz. Bu amaçla filtreleme kullanacağız. Eğer bir rakam beşe bölündüğünde kalan üç ise istediğimiz koşulları sağlıyor.

In [3]:
#3 ve 8 rakamlarını seçmek için filtreleme kullanacağız.
#Filtrelemeyi etiket değerlerine (y) bakarak yapacağız. 
#Etiket değeri beşe bölündüğünde kalan üç ise bu gözlemleri veri kümesinde bırakıyoruz.
X= X[y%5 == 3]
y= y[y%5 == 3]

#Son olarak etiketleri 0 ve 1 değerlerine çevirelim.
#Rakam 3 ise etiket 0, 8 ise 1 olacak.
y = (y==8)*1
print('Verinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X)))
print('Etiketlerin boyutları (Gözlem) = ' + str(np.shape(y)))
Verinin boyutları (Gözlem, öznitelik) = (357, 64)
Etiketlerin boyutları (Gözlem) = (357,)

Öğrenen modellerin başarısını sınamak için veri kümesini öğrenme (train) ve sınama (test) olarak ikiye bölelim. Bu da scikit-learn altında yapılabilecek bir işlem. Burada dikkat etmemiz gereken, veri kümesini bölerken etiketlerin yüzdelerini korumak. Bu sayede veri kümesinin sadece bir rakamdan oluşması gibi durumların önüne geçmeyi hedefliyoruz. stratify argümanı ile veri kümesini bölerken etiket değerlerini de hesaba katıyoruz.

In [4]:
#Stratify değeri veri kümesinin etiket yüzdelerini korumak için kullanılıyor.
#Öğrenme veri kümesini küçük tutarak sonuçların çok iyi olmasını engelliyoruz.
#random_state değeri sonuçların her seferinde aynı çıkmasını sağlamak için kullanılıyor.
X_train, X_test, y_train, y_test = train_test_split(X,y, train_size = 0.5, test_size = 0.5, random_state = 0, stratify = y)

print('Öğrenme verisinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X_train)))
print('Sınama verisinin boyutları (Gözlem, öznitelik) = ' + str(np.shape(X_test)))
Öğrenme verisinin boyutları (Gözlem, öznitelik) = (178, 64)
Sınama verisinin boyutları (Gözlem, öznitelik) = (179, 64)

Veri kümesini ikiye böldük. Şimdi sınıflandırma için karar ağacı ve rastgele orman yöntemlerini kullanıp karşılaştıracağız. scikit-learn API’ının üç adımlık basit bir kullanımı var. Şimdi bu adımları inceleyelim.

Kullanacağımız sınıfa ait bir örnek oluşturma

Örnek olarak bir karar ağacı oluşturmak ya da eksik değerleri ortalama değerle doldurmak istiyorsunuz. Bu amaçla gerekli sınıflara (class) ait örnekleri istediğiniz parametrelerle oluşturmanız gerekiyor..

dt adında bir karar ağacı oluşturmak için DecisionTreeClassifier sınıfını kullanıyoruz:

dt = DecisionTreeClassifier()

Eksik değerleri ortalama değerle değiştirmek için ise Imputer sınıfını kullanacağız. NaN şeklinde olan eksik değerleri ortalama (mean) değerle değiştirmek istersek bunu kullanacağımız argümanlarla belirtmemiz gerekiyor.

mean_imputer = Imputer(missing_values = 'NaN', strategy = 'mean')

Aşağıda dt adında bir karar ağacı ve rf adında bir rastgele orman örneği tanımlıyoruz.

In [5]:
#Karar ağaçları
from sklearn.tree import DecisionTreeClassifier
#Rastgele orman
from sklearn.ensemble import RandomForestClassifier

#Karar ağacı modelini oluşturalım. 
#random_state değeri sayesinde sonuçların rassal olarak değişmemesini sağlıyoruz.
dt = DecisionTreeClassifier(random_state = 0)

#Rastgele orman modelini oluşturalım.
rf = RandomForestClassifier(random_state = 0)

Oluşturduğumuz örneğin öğrenmesini sağlama (fit)

Bir önceki aşamada oluşturduğumuz örneğin veri üzerinde öğrenmesi fit fonksiyonuyla yapılıyor. Örneğin bir karar ağacını öznitelik ve etiketleri kullanarak eğitmek için fitfonksiyonunu aşağıdaki gibi kullanabiliriz:

dt.fit(X_train, y_train)

Bu sayede öğrenme verisi üzerinden bir karar ağacı modeli oluşturulur.

Eksik değerleri doldurmak için de fit fonksiyonunu kullanacağız. Ancak burada fit fonksiyonu sadece yapacağımız işlemi tanımlıyor. Aşağıdaki satırda X_train matrisindeki eksik değer içeren sütunlar için ortalama değer hesaplanıyor.

mean_imputer.fit(X_train)

Şimdi yukarıda oluşturduğumuz karar ağacı ve rastgele orman modellerini eğitelim.

In [6]:
#Modellerin öğrenmesini sağlayalım.
dt.fit(X_train,y_train)
rf.fit(X_train,y_train)
Out[6]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

Sonuçları elde etmek (predict/predict_proba ve transform)

Oluşturduğunuz modelleri eğittikten sonra sonuçları elde etmek için kullanabileceğiniz iki farklı fonksiyon tipi var.

  • predict: Regresyon, sınıflandırma, kümeleme gibi yöntemler kullanarak yapacağınız çalışmalarda tahmin edilen etiket bilgisini predict fonksiyonuyla elde edebilirsiniz. Sınıflandırma problemlerinde gözlemlerin sınıflara ait olma olasılıklarını elde etmek istiyorsanız predict_proba fonksiyonunu kullanmanız gerekiyor.

Yukarıda oluşturduğumuz karar ağacı için etiketleri elde etmek için aşağıdaki satıra ihtiyacımız var:

y_pred = dt.predict(X_test)

Eğer etiketleri değil de olasılıkları öğrenmek istiyorsak predict_proba fonksiyonunu kullanmamız gerekiyor. Sonuçlar her etikete ait olma yüzdesini içeriyor.

y_pred_proba = dt.predict_proba(X_test)

  • transform: Veriyle ilgili yapacağımız dönüştürme işlemlerinde ise transform fonksiyonunu kullanacağız. Dönüştürme işlemleri eksik veriyi doldurma, veriyi ölçeklendirme gibi alanlarda karşımıza çıkıyor. Aynı zamanda bir matrisi çarpanlarına ayırmak gibi işlemler için de transform fonksiyonu kullanılıyor.

Eksik değerleri doldurmak için aşağıdaki satırı kullanabiliriz:

X_test = mean_imputer.transform(X_test)

Şimdi kullandığımız iki modeli sınama veri kümesinde kullanarak etiketleri ve gözlemlerin etiketlere ait olma olasılıklarını hesaplayalım.

In [7]:
#Sınama verisinin etiketlerini elde edelim.
y_pred_dt = dt.predict(X_test)
#Sınama veri kümesinin sınıflara ait olma olasılıklarını alalım.
y_pred_proba_dt = dt.predict_proba(X_test)

#Aynı adımları rastgele orman yöntemi için tekrarlayalım.
y_pred_rf = rf.predict(X_test)
y_pred_proba_rf = rf.predict_proba(X_test)

Burada dikkat etmemiz gereken bir nokta fit işlemlerini öğrenme, predict ve transformişlemlerini ise sınama verisi üzerinden yapmak. Yapacağımız çalışmalardaki amacımız öğrenme veri kümesiyle yakaladığımız örüntüleri sınama verisi üzerinde denemek. Yani, sınama veri kümesinin sadece son aşamada kullanılması gerekiyor. Eksik değerleri doldurmak gibi konularda da öğrenme verisiyle elde ettiğimiz bilgileri (örnek olarak ortalamayı) sınama verisinde kullanıyoruz. Sınama veri kümesi için de fit fonksiyonunu kullanmak sıklıkla yapılan bir hata.

Aşağıdaki satırlarda öğrenme verisindeki sütunlar için ortalama değeri bulup eksik değerleri dolduruyoruz. Daha sonra da sınama verisindeki sütunlar için ortalama değerleri bulup eksik değerleri doldurmak için kullanıyoruz. Oysa ki yapmamız gereken sınama verisinde de öğrenme verisindeki ortalamaları kullanmak.

mean_imputer.fit(X_train)
X_train = mean_imputer.transform(X_train)
mean_imputer.fit(X_test)
X_test = mean_imputer.transform(X_test)

5.Hafta Phyton Programlama Dili

Fonksiyonlar

Yazı dizimizin şimdiye kadarki bölümlerinde bir programı inşa etmek için gereken bütün yapı taşlarını gördük. Prosedürel programlama denen paradigma içinde programlar birbiri arkasından işlenir, bir karar verilmesi gerektiğinde program akışı iki yoldan birini seçer, veya bir döngü içindeki bir kod parçası tekrarlanır.

Teorik olarak, her türlü programı yazmak için bu yapılar yeterli. Ancak, Yogi Berra’nın dediği gibi: Teoride teori ve pratik arasında fark yoktur, ama pratikte vardır.

Kod yazarken işlemleri sık sık farklı yerlerde tekrarlamamız gerekir. Söz gelişi, bir yatırımın belli bir dönem sonunda bileşik faizle ne miktara ulaştığını yazmak için bir döngü yazabiliriz. Bu tür bir işlemi büyük bir program içinde değişik yerlerde (mesela farklı yatırım araçları için) kullanmamız gerekebilir. Programcılar böyle tekrarlanan işler için aynı kodu tekrar tekrar yazmaktansa, bunları bir fonksiyon(prosedür veya yordam olarak da bilinir) olarak paketleyip kullanmayı tercih ederler. Fonksiyon kullanmak sayesinde:

  • Aynı kodu defalarca yazmak gerekmez.
  • Tekrarlama yüzünden doğacak hatalar ortadan kalkar.
  • Bellek (RAM) gereksiz yere dolmaz. Kod parçası onlarca kere tekrarlanmak yerine bir kere yazılır.
  • Programcı küçük ayrıntılara tekrar tekrar kafa yormak zorunda kalmaz.
  • İşleri küçük birimlere bölmek, programlama hatalarını bulmayı kolaylaştırır.
  • Programlama dilinin çekirdek tanımında bulunmayan üst seviye işlemleri tek komutla yapmayı sağlar.
  • Fonksiyon kütüphaneleri, uzmanlaşmış programcılar tarafından hızlı ve verimli hale getirilebilir.

Bu faydalar sadece Python değil, her türlü programlama dili için geçerlidir tabii.

Bir fonksiyon bir kara kutu gibi düşünülebilir: Aldığı parametreler onun girdisi, verdiği (“döndürdüğü”) değer ise çıktısıdır. Fonksiyonlara istediğiniz sayıda parametre verebilirsiniz. Parametre almayan ve/veya geriye bir değer vermeyen fonksiyonlar da olabilir.

Kütüphane fonksiyonları kullanma

Bir kütüphane belli bir işlev için hazırlanan fonksiyonların topluluğudur. Bir kütüphane matematik fonksiyonlarını toplarken, başka bir kütüphane kelime işleme, bir başkası ağ iletişimi, bir başkası oyun modülleri barındırıyor olabilir. Kütüphaneler bir dilin resmi tanımına dahil olabilir ve kurulumda beraber gelebilir (bu durumda onlara standart kütüphane denir), veya üçüncü kişiler tarafından hazırlanmış olabilir.

Python dili çok zengin bir standart kütüphaneye sahiptir. Matematik işlemleri, istatistik işlemleri, gün ve saat işlemleri, dosya sıkıştırma, internet protokolleri, HTML, işletim sistemi yönetimi, grafik arayüz oluşturma, ve daha bir çok işlem için gereken hazır fonksiyonlar Python ile birlikte gelir. Bunların dışında yüzlerce başka kütüphane de mevcuttur, istediğinizde bunları sisteminize kurup kullanabilirsiniz. Daha sonraki yazılarda kendi kütüphanelerimizi nasıl oluşturacağımızı da göreceğiz. Bu yazıda sadece matematik fonksiyonları kütüphanesini örnek olarak kullanacağız.

Kütüphaneler diskimize kurulu olarak hazır bekliyor olsalar da, onları kullanmak için önce importkomutuyla yorumlayıcıya yüklememiz gerekir.

In [1]:
import math
print( math.sqrt(2) )
print( math.sin(math.pi/2) )
1.4142135623730951
1.0

Burada math.sqrt(2) ifadesi bir fonksiyon çağrısıdır. Matematik modülü math içindeki karekök fonksiyonu sqrt çağrılır ve 2 argümanı verilir. Aradaki nokta bir üyelik belirtir; sqrt fonksiyonu math modülünün altındadır. Keza math.sin aynı modülün altındaki sinüs fonksiyonudur, math.pi ise $\pi$ sayısıdır.

Siz ayrıca pi veya sqrt isimli değişkenler veya fonksiyonlar tanımlamış olsanız da, onlar ile bu isimler karışmaz; pi ile math.pi farklıdır. Burada math bir isim alanı (namespace) oluşturur; kendi tanımlarını ayrı tutar.

Yükleme sırasında modülün adını değiştirebiliriz. Özellikle uzun isimli modülleri daha kısa isimle kullanmak için bu özellik faydalı olur.

In [2]:
import math as m
print( m.sqrt(2) )
print( m.sin(m.pi/2) )
1.4142135623730951
1.0

Veya, modüldeki bütün isimlere ihtiyacınız yoksa, onları mevcut isim alanınıza tek tek belirleyerek alabilirsiniz. İsim değiştirme burada da geçerlidir. Modül içindeki isimleri değiştirerek alabilirsiniz.

In [3]:
from math import sqrt, sin
from math import pi as π
print( sqrt(2) )
print( sin(π/2) )
1.4142135623730951
1.0

(Jupyter defterinin kod hücresinde π yazmak için \pi yazın ve Tab tuşuna basın.)

Başka bir alternatif, modüldeki bütün isimleri mevcut isim alanına yüklemektir.

In [4]:
from math import *
cos(pi), tan(pi/4)
Out[4]:
(-1.0, 0.9999999999999999)

Ancak bu usül Python programcıları tarafından tavsiye edilmez. Bir modül adı kullanmak, ister math ister kısaca m, bir isim alanı yaratır ve isim çatışmalarını engeller. Varsayalım ki pi veya tan değişkenlerini kodunuzda bir yerlerde önceden başka bir anlamda tanımladınız. Modülü import * ile yüklemekle önceki tanımları silersiniz, ve kodunuz biraz karmaşık ise bunu farketmeyebilirsiniz bile. Özellikle büyük modüllerde pek çok değişik isim gizli olabilir ve neyi sildiğinizi farketmeyebilirsiniz bile. En doğrusu, birazcık daha fazla yazmayı göze alıp bir modül ismi kullanmaktır.

Bir modülde tanımlı bütün isimlere dir fonksiyonuyla erişilebilir.

In [5]:
import math
dir(math)
Out[5]:
['__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'acos',
 'acosh',
 'asin',
 'asinh',
 'atan',
 'atan2',
 'atanh',
 'ceil',
 'copysign',
 'cos',
 'cosh',
 'degrees',
 'e',
 'erf',
 'erfc',
 'exp',
 'expm1',
 'fabs',
 'factorial',
 'floor',
 'fmod',
 'frexp',
 'fsum',
 'gamma',
 'gcd',
 'hypot',
 'inf',
 'isclose',
 'isfinite',
 'isinf',
 'isnan',
 'ldexp',
 'lgamma',
 'log',
 'log10',
 'log1p',
 'log2',
 'modf',
 'nan',
 'pi',
 'pow',
 'radians',
 'sin',
 'sinh',
 'sqrt',
 'tan',
 'tanh',
 'tau',
 'trunc']

Modüldeki belli bir fonksiyonun nasıl kullanıldığını hatırlamanız gerektiğinde help fonksiyonunu kullanabilirsiniz. Bu işlemle, fonksiyonun içine gömülü belgeleme dizesi (docstring) ekrana yazılır. Belgeleme dizelerinin nasıl oluşturulacağını bu yazının sonunda okuyabilirsiniz.

In [6]:
help(math.sin)
Help on built-in function sin in module math:

sin(...)
    sin(x)
    
    Return the sine of x (measured in radians).

Fonksiyon tanımlama

Şimdi kendimiz nasıl fonksiyon yaratabileceğimizi görelim. Python’da fonksiyonlar def kelimesiyle tanımlanır. Mesela:

In [7]:
def f1(x):
    print(x)

f1(3)
3
In [8]:
f1("merhaba"), f1(3.0*4.25), f1( (2,37) )
merhaba
12.75
(2, 37)
Out[8]:
(None, None, None)

Bu fonksiyon basit bir iş yapıyor, aldığı parametreyi olduğu gibi ekrana basıyor. Herhangi bir nesne alabildiğine dikkat edin. Fonksiyonun geri verdiği bir değer yok. Bu yüzden yukarıdaki komutta çıktı hücresinde (None, None, None) görüyoruz.

Fonksiyonların bir değer geri vermesi istiyorsak return komutunu kullanırız. Bu komut, arkasından gelen ifadenin değerinin, fonksiyonu çağıran programa bildirilmesini sağlar ve fonksiyonun çalışmasını bitirir.

Aşağıdaki fonksiyon aldığı iki parametreye çarpma işlemini uygular ve sonucu geri verir:

In [9]:
def carp(a,b):
    return a*b

carp(2,-7)
Out[9]:
-14

Geri verilen değeri daha sonraki bir işlemde kullanmak için bir değişkene atayabilirsiniz.

In [10]:
y = carp(2, -7)
y + 3
Out[10]:
-11

C, C++, Fortran, Java gibi daha katı dillerden farklı olarak, Python’da fonksiyon tanımlarken, parametrelerin ne tipte (tamsayı, kayan noktalı sayı, dize, liste, vs.) olduğu belirtilmez. Bu özellik sayesinde Python programları farklı veri tipleriyle işlem yapma kolaylığı sağlar. Mesela carp bir dize ile bir tamsayı almaya itiraz etmez. Çarpma işlemini bu iki tiple tanımlandığı gibi yapıp sonucu geri verir.

In [11]:
carp("merhaba",3)
Out[11]:
'merhabamerhabamerhaba'

Ama bu kolaylığın bir bedeli vardır: Fonksiyonun içinde, kullandığınız veri tipleri ile ilgili işlemlerin uyumlu olması gereklidir. Sözgelişi, iki dizeyi “çarpmak” bir hata mesajına yol açar, çünkü dizeler arasında * işlemi tanımlı değildir.

In [12]:
carp("merhaba","dunya")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-5dfbcca2560b> in <module>()
----> 1 carp("merhaba","dunya")

<ipython-input-9-c813e8533fc7> in carp(a, b)
      1 def carp(a,b):
----> 2     return a*b
      3 
      4 carp(2,-7)

TypeError: can't multiply sequence by non-int of type 'str'

Böyle hatalardan kaçınmak için birkaç yol vardır. Bunlardan biri assert komutu ile belli şartların sağlanıp sağlanmadığını önceden yoklamak, bir diğer ise fonksiyonun içinde istisna işlemi (“exception handling”) yapmaktır. Böylece belli bir hata (meselâ yukarıdaki gibi TypeError) oluştuğunda, programı durdurmadan akışı düzenlemek mümkün olur. Bu konulara sonraki bölümlerde yer vereceğiz.

Birkaç tane değer geri verme

Fonksiyonlar her tipte nesne geri verebilirler. Bir çokuz nesnesi veren bir fonksiyon kullanarak, birden fazla değer çıkarma davranışı taklit edilebilir:

In [13]:
def f(x, y):
    return x+y, x-y

toplam, fark = f(3,5)
print("Toplam = {}, Fark = {}".format(toplam,fark))
Toplam = 8, Fark = -2

Fonksiyon veren fonksiyonlar

Python dinamik bir dildir: Programın işleyişi sırasında komutlar yeni nesnelerin üretilmesini ve işlenmesini sağlar. Fonksiyonlar da dinamik olarak def komutuyla yaratılır. Buna karşılık, C gibi derlenen diller böyle davranmaz. Bu tür dillerde fonksiyonlar, program henüz çalıştırılmadan, derleme aşamasında yaratılır ve işletilebilir ikili koda gömülür. Python gibi dillerin dinamik yapısı sayesinde, fonksiyonların başka komutlar ve bloklar içinde, mesela sadece bir şart doğru olduğunda tanımlanmasını sağlayabiliriz.

In [14]:
test = True
if test:
    def f1(): print(5)
else:
    def f2(): print(10)
In [15]:
f1()
5
In [16]:
f2()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-16-fdec4c1c071f> in <module>()
----> 1 f2()

NameError: name 'f2' is not defined

Bir fonksiyon tanımlanmasında, önce belirttiğimiz kod parçasını içeren bir fonksiyon nesnesi yaratılır, sonra bu nesne ona verdiğimiz isme bağlanır. Bu anlamda def komutu atama (=) işlemi gibi çalışır. Bunun bir yan faydası, varolan bir fonksiyona başka isimler verebilme imkânıdır.

In [17]:
yenifonk = f1
yenifonk()
5

İki ismin de aynı nesneye işaret ettiğini is komutuyla doğrulayabiliriz.

In [18]:
yenifonk is f1
Out[18]:
True

Yine aynı dinamik özellik sayesinde, fonksiyon veren fonksiyonlar (“fonksiyon fabrikaları”) tanımlanabilir.

In [19]:
def kuvvetfonk(n):
    def fonk(x):
        return x**n
    return fonk

Buradaki kuvvetfonk fonksiyonu, aldığı parametreyi kullanarak yarattığı bir fonksiyon nesnesini verir. Bu fonksiyon nesnesine bir isim atayıp bu isimle çalıştırabiliriz.

In [20]:
kare = kuvvetfonk(2)
kup = kuvvetfonk(3)
kare(5), kup(5)
Out[20]:
(25, 125)

Aslında bu fonksiyon nesneleri bir isme atamadan da çağrılabilir, ama her seferinde bu fonksiyonlar baştan yaratılacağı için hesaplama açısından verimsiz olur.

In [21]:
kuvvetfonk(2)(5), kuvvetfonk(3)(5)
Out[21]:
(25, 125)

Fonksiyon alan fonksiyonlar

Fonksiyonlar, başka fonksiyonları parametre olarak alabilirler. Basit bir örnek olarak, bi=af(i)toplamını veren bir fonksiyon yazalım.

In [22]:
def fntoplam(f, a, b):
    i = a
    toplam = 0
    while i<=b:
        toplam += f(i)
        i += 1
    return toplam

def f1(x):
    return 1.0/x

def f2(x):
    return 2.0**-x
In [23]:
fntoplam(f1, 1, 10)
Out[23]:
2.9289682539682538
In [24]:
fntoplam(f2, 1, 10)
Out[24]:
0.9990234375

Değiştirilebilir parametreler

Fonksiyonlara, listeler gibi değiştirilebilir (mutable) parametreler veriyorsanız, ve bunlar fonksiyon içinde değiştiriliyorsa, bu değişiklik kalıcı olur.

In [25]:
def f(x):
    x[0] = -10
    print(x)

x = [1,2,3]
f(x)
[-10, 2, 3]
In [26]:
x
Out[26]:
[-10, 2, 3]

Değişken görünürlüğü, yerel ve global değişkenler

Bir fonksiyon blokunun dışında ve içinde aynı isimde değişkenler kullanırsanız, içeride olanın değeri kullanılır olur. Fonksiyon, dıştaki değişkenin değerini değiştirmez.

In [27]:
x = 10
def f():
    x = 20
    print(x)

f()
20
In [28]:
x
Out[28]:
10
 Python bu iki x ismini farklı değişkenler olarak görür. İkinci x bir yerel değişkendir ve sadece ffonksiyonu içinde tanımlıdır. Birincisi ise global görünürlüğe sahiptir; aşağısında tanımlanan bütün fonksiyonlarda kullanılabilir. Yukarıdaki örnekte f fonksiyonu tanımı altında x=20 satırını silersek fonksiyon ekrana global x değeri olan 10’u basacaktır.

Bir seviye daha karmaşık bir örnek olarak, f fonksiyonu içinde başka bir fonksiyon tanımlayalım.

In [29]:
x = 10
print("x =",x)
def f():
    x = 20
    print("f içinde x =",x)
    def g():
        x = 30
        print("g içinde x =", x)
    g()
f()
x = 10
f içinde x = 20
g içinde x = 30
 Bir değişken ismine atanmış değerin tespit edilmesi için genel kural şöyledir: Önce program akışının bulunduğu blok içinde bir tanım yapılmış mı diye bakılır. Eğer en içteki blokta bir tanım bulunmazsa, onu çevreleyen dış bloka, yoksa onun da dış blokuna bakılır. En dış bloka gelindiğinde global değişkenler içinde olup olmadığına bakılır. En son olarak öntanımlı (“built-in”) isimler kontrol edilir.

Peki, diyelim ki tam tersini istiyoruz. Yani, bir fonksiyon içinde, fonksiyonun dışında tanımlanmış bir değişkene yeni bir değer atamak istiyoruz. Somut olarak, iki önceki örnekte, fonksiyon çalıştıktan sonra x‘in 20 olmasını istiyoruz. Bunu, fonksiyon içinde global komutuyla sağlarız.

In [30]:
x = 10
def f():
    global x
    x = 20

f()
print("x =",x)
x = 20
Ancak, global değişkenlerden mümkün olduğunca kaçınmak gerekir. Fonksiyonlara giriş bilgisini parametrelerle sağlamak ve çıkış değerini return komutu aracılığıyla almak daha iyidir. Böylece fonksiyonların düzgün bir akış içinde çalışmasını, bileşenlerin birbirine kolayca bağlanan modüler bir yapıda olmasını, “aldığı belli verdiği belli” olmasını sağlarız. Bu şekilde programlar daha okunaklı ve anlaşılır olur. Global değişkenler ise hem giriş hem çıkış kanalı oldukları için bu akışı bozarlar. Globallerin fazla kullanıldığı programları hem okumak zordur, hem de bilgi akışının karışık bir yumak haline gelmesi mümkündür, hata yapma ihtimali artar. Fonksiyonlara veriyi her zaman fonksiyon parametreleriyle vermeye çalışın.

Belgeleme dizeleri

Fonksiyon tanımına bir belgeleme dizesi (docstring) eklemek mümkündür. Bir belgeleme dizesi, fonksiyon başlığının hemen altında başlayıp biten bir açıklama metnidir. Normal bir Python dizesinden hiç bir farkı yoktur, ama genellikle üç tırnak (""") ile sınırlandırılırlar, böylece birkaç satıra yayılabilirler. Fonksiyonun çalışmasını etkilemezler. Birçok Python aracı, sözgelişi etkileşimli help fonksiyonu bu dizeleri otomatik olarak alıp kullanabilir.

In [31]:
def fntoplam(f, a, b):
    """f(a) + f(a+1) + ... + f(b) toplamını döndürür."""
    i = a
    toplam = 0
    while i<=b:
        toplam += f(i)
        i += 1
    return toplam
In [32]:
help(fntoplam)
Help on function fntoplam in module __main__:

fntoplam(f, a, b)
    f(a) + f(a+1) + ... + f(b) toplamını döndürür.

 Bütünleşik geliştirme ortamlarında (IDE’lerde) çalışırken, fonksiyonu yazdığınız sırada bu belgeleme dizesine ulaşabilirsiniz. Sözgelişi Jupyter defterinde Shift-Tab basarsanız bir yardım penceresi açılır.

4.Hafta Phyton Programlama Dili

Listeler

Listeler oldukça yararlı ve fonksiyonel bir Python değişken türüdür. Kullanım amaçları bir veri topluluğunu tek çatı altında toplayarak kolay ulaşılabilir hale getirmektir. Üstelik aynı stringler gibi ,indekslenir,parçalanır ve işlemlere tabi tutulabilirler. Bu sayede ortak veya ortak olmayan kümeler halinde bir araya getirebileceğiniz verileri aşağıda örneklerini göreceğiniz birçok fonksiyon ile kullanabilir ve birçok işleme tabi tutabilirsiniz.

Liste oluşturma

Python array değişken türünün en önemli özelliklerinden birisi dizi içinde farklı değişken türlerini bir arada tutabilmenizdir. Böylece oldukça kolay bir şekilde farklı türleri aynı dizide depolayabilirsiniz. Öyleyse birçok farklı yöntemle liste/dizi nasıl oluşturulur hemen onu görelim.

# boş liste değişkeni 
liste =  []
# dizi/liste(array) oluşturmanın farklı bir tarzı
liste =  list()
# sadece int değerler tutan dizi/liste
liste =  [1,2,3,4,5,6,7]
# string tutan array
liste =  list("İstanbul","Ankara","İzmir")
# farklı değişken türleri tutan liste isimli array değişkeni
liste =  [10,11,12,"Python",3.14,51.035]
# string parçalayarak dizi/liste oluşturma
isim = "Kerteriz"
liste =  list(isim)
>>> ['K','e','r','t','e','r','i','z'] // yukarıdaki işlem sonucu oluşan dizi

Liste İndexleme ve Parçalama İşlemleri

Yukarıda bir dizinin nasıl oluşturulduğunu birçok yöntemle gördük. Sizde bir array oluşturmaya çalıştığınızda herhangi biri sayesinde kolaylıkla array oluşturabilirsiniz. Şimdi ise aşağıda diziler üzerinde kullandığımız temel index ve parçalama işlemlerini inceleyelim

# array indexleme /basit dizi
liste = ["Elma","Armut","Kivi","Muz"]
liste[2]

>>> "Kivi"
# array indexleme /iç içe dizi
liste1 = [1,2,3]
liste2 = [4,5,6]
liste3 = [7,8,9]

yeniliste = [liste1,liste2,liste3]
>>> [[1,2,3],[4,5,6],[7,8,9]] //dizinin son hali

yeniliste[1,2]
>>> 6
# Listenin sonuncu elemanını gösterme
liste = [3,4,5,6,7,8,9]
liste[len(liste)-1]

>>> 9
# Baştan 4. indekse kadar (dahil değil)
liste = [3,4,5,6,7,8,9]
liste[:4]

>>> 3,4,5,6
# 2. ve 4. arasını alma
liste = [3,4,5,6,7,8,9]
liste[2:4]

>>> 5,6
# 3. indexten sonuna kadar alma
liste = [3,4,5,6,7,8,9]
liste[3:]

>>> 6,7,8,9

Liste/Dizi Elemanı İşlemleri

Şimdi ise dizi elemanları üzerinde kullandığımız temel methodlara bakalım ve ne tür işlemler var inceleyelim.

# Listeleri birleştirme
liste1 =  [1,2,3,4,5]
liste2 =  [6,7,8,9,10]
liste1 + liste2

>>> [1,2,3,4,5,6,7,8,9,10]
# Diziye eleman dahil etme
liste =  ["Manisa","Düzce","Bolu"]
liste + ["Çankırı"]

>>> ["Manisa","Düzce","Bolu","Çankırı"]
# Listedeki elemanı değiştirme /Yöntem1
liste =  [1,2,3,4,5]
liste[2]="Merhaba"

>>> [1,2,"Merhaba",4,5]
# Listedeki elemanı değiştirme /Yöntem2
liste =  [1,2,3,4,5]
liste[:2]=[10,20]

>>> [10,20,3,4,5]
# Dizi çarpma işlemi ile tekrarlama
liste =  [1,2,3,4,5]
liste = liste*2

>>> [1,2,3,4,5,1,2,3,4,5]

Liste/Dizi Temel Fonksiyonları

Artık Python diziler için en kullanışlı ve bilmeniz gereken array (dizi/liste) fonksiyonları neler bunları görelim.

len methodu ile dizinin eleman sayısını öğrenme

# Liste eleman sayısı
liste = [3,4,5,6,6,7,8,9,0,0,0]
len(liste)

>>> 11

append methodu ile diziye eleman ekleme

# Dizi sonuna eleman ekleme
liste =  [1,2,3,4,5]
liste.append(6)

>>> [1,2,3,4,5,6]

pop methodu ile diziden eleman çıkarma

# Dizi sonundaki elemanı çıkarma
liste =  [1,2,3,4,5]
liste.pop()

>>> [1,2,3,4]
# Dizide istediğim indexteki elemanı çıkarma /çıkan elemanı ekrana basar
liste =  ["Ali","Yunus","Deniz","Asım"]
liste.pop(2)

>>> Deniz

sort methodu ile diziyi küçükten büyüğe doğru sıralama

# Dizi elemanlarını küçükten büyüğe doğru sıralar
liste =  [43,35,78,13,5,86,90]
liste.sort()

>>> [5, 13, 35, 43, 78, 86, 90]

sort methodu ile diziyi büyükten küçüğe doğru sıralama

# Dizi elemanlarını büyüktenten küçüğe doğru sıralar
liste =  [43,35,78,13,5,86,90]
liste.sort(reverse=True)

>>> [90, 86, 78, 43, 35, 13, 5]

NOT: string elemanlarından oluşan dizileride sıralayabilirsiniz. Bu durumda dizinizdeki elemanlar alfabetik sıraya göre sıralanmış olacaktır.

Demetler

Demetler yine aynı şekilde dizi yapısından haberdar olan arkadaşlarımız için diziyi benzemektedir. Bir önceki dersimizde listeleri anlatmıştık buda aynı şekildedir. Tabi tamamen aynı olmalarına olanak yok, bu nedenle demetlerdeki veriler değiştirilemiyor, eklenemiyor, silinemiyor.

1

Şekildeki gibi demetler gösterilir ve tanımlanır. Görüldüğü üzere boş demette oluşturabiliyoruz tabi ekleme yapamadığımız için boş demet oluşturmak oldukça anlamsız olacaktır.

Bazen elimizdeki veri kümesinin ne olduğunu öğrenmemiz gerekebilir bu gibi durumlarda tipini sorgulama işlemi yaparız. Aşağıdaki gibi yapıldığı taktirde hangi sınıfa ait olduğunu kolaylıkla öğrenebiliriz.

2

Peki şimdi demetlere veri eklenmediğini değiştirilmediğini biliyoruz, biz biraz bunun üzerine oynasak ve liste ile demeti birleştirsek.

3

Görüldüğü gibi birleştirme işlemini gerçekleştirdik. Demetin içine bir liste yerleştirdik ve bu listenin verisi çekmeyi ve güncellemeyi şekildeki gibi gerçekleştirdik. Bunu anlamadıysanız bilgisayarda deneyerek yapmayı deneyebilirsiniz. İşinizi kolaylaştıracaktır, matris şeklinde düşünülebilir.

Listelerin olduğu gibi demetlerinde metotları var fakat bunlar o kadarda fazla değil, index ve count’dan ibaret.

-index() : İstenilen elemanın demetteki indisini verir.

-count() : İstenilen elemanın demet içerisinde kaç adet olduğunu verir.

4

 

3.Hafta Phyton Programlama Dili

Döngüler

Şimdiye kadar öğrendiğimiz kadarıyla yaptığımız programlar dikkat ettiyseniz sadece 1 kez çalışıyordu. Şayet kullanıcı bir kez daha programı kullanmak isterse yeniden çalıştırması gerekecek ve bu durum hiç iyi karşılanmayacaktı neyse ki imdadımıza Döngüler(Loops) yetişti.

While Döngüsü

Yine ingilizce bir kelime olan while, iken, olduğu sürece anlamındadır. Öncelikle while döngüsünün temellerini basit bir şekilde kavramaya çalışalım.

a=3
while a == 3:

a adında bir değişken tanımlayıp değer verdik ve while döngüsüne a değeri 3 rakamına eşit olduğu sürece… gördüğünüz gibi eşit olduğu sürece dedik, programımıza ne yapması gerektiğini söylemedik.

a=3
while a == 3:
    print("sonsuza kadar ekrana yaz...")

programımız sonsuza kadar ekrana yazdırma işlemi yapmaya devam eder. Burada programımızı sonsuz bir döngüye sokmuş olduk (infinite loop). Aslında sonsuz döngüler genellikle program hatasına işaret eder. O yüzden en doğru yaklaşım öyle bir kod yazalım ki programımız sonsuz döngüye girmesin ve a değişkeni 3 olduğunda dursun. (Bu arada sol taraftaki kırmızı kareden programı durdurmayı unutmayın)

a = 3
while a < 10:
    print("sonsuza kadar ekrana yaz...")

Programımızın sonsuz döngüye girmesini engellemek için bir koşul koyduk ama yine olmadımı? Programı durduralım.. Biz burada a değeri 10 sayısından küçük olduğu sürece ekrana yaz dedik. Aslına bakarsanız a sayısı her zaman 10 rakımından küçük olduğu için programımız sonsuz döngüye girecektir. Şimdi bu problemi nasıl aşabileceğimizi öğrenelim:

a = 3
while a < 10:
    a += 1
    print("sonsuza kadar ekrana yaz...")

Bilmediğimiz birşeyle karşılaştık der gibisiniz bunlara değer atama işleçleridenir. Buradaki a += 1 ifadesi değişkenimizin değerini 1 artıracak ve elde edilen sonucu tekrar a değişkenimize atayacak. Değişkenin değeri 10 rakamına ulaştığında ekrana yazdırma işlemi sonlanacak.

Değer Atama İşleçleri

Aşağıdaki örnekleri inceleyerek pekiştiriniz.

#degiskenimiz
a = 20
# += isleci toplama yapar
a +=5
print(a)
# -= isleci cikarma yapar
a -=2
print(a)
# /= isleci bolme islemi yapar
a /= 2
print(a)
# *= isleci carpma islemi yapar
a *= 2
print(a)
# %= isleci mod alma islemi yapar
a %= 2
print(a)
# **= isleci mod alma islemi yapar
a = 6
a **= 2
print(a)
While döngüsüyle ilgili örneklerimize devam edelim.
while True:
    print("Python!")
while true ifadesiyle programımıza true olduğu müddetçe çalış demiş olduk. Programımız yine istemimizce sonsuz döngüye girmiş oldu programı durdurup sorunun üstesinden break deyimi ile nasıl geldiğimizi inceleyelim.
while True:
    soru = input("Python programlamayi ogrenmek kolaymi?")
    if soru == "cik":
        break
Sorunun değeri cik olana kadar döngü çalışmaya devam eder. cik cevabını aldığında döngü break komutu sayesinde kırılır(sonlanır).

for döngüsü

for döngüsü python programlama dilinde neredeyse geliştirilen tüm programlarda kullanılır.  for döngüsü tıpkı while döngüsü programlarımızın birden fazla çalışmasını sağlar. while döngüsünden daha yeteneklidir. For döngüsünün söz dizimi aşağıdaki gibidir.
for değişken_adı in değişken:
    yapılacak_işlem
Örnek:
sayilar = "2468"
for sayi in sayilar:
    print(int(sayi) * 2)
Cıktı
4
8
12
16
Yukarıdaki örnekte sayilar isimli değişkenin herbir öğesini sayi olarak adlandırdık ve int() fonksiyonu yardımıyla bu öğeleri sayıya çevirerek 2 ile çarptık. for döngüsü içerisinde bulunduğu öğeleri tek tek ele alıp işlem yapan bir öğedir.
Döngülerle ilgili daha verimli kodlar yazabilmemiz için bazı fonksiyon ve deyimlerden bahsedeceğiz.
range Fonksiyonu
aralık anlamına gelen range fonksiyonu, python programlamada belli aralıkta bulunan sayıları göstermek için kullanılır.
for i in range(0, 5):
    print(i)
Cıktı:
0
1
2
3
4
Bu örnek ile range fonksiyonunu kullanarak 0 ve 5 arasındaki sayıları for döngüsü kullanarak yazdırdık. range fonksiyonuna 2 parametre verdiğimizi görüyorsunuz. Eğer sadece 5 parametresini verseydik yine aynı işlemi yapacaktı. Fonksiyona parametre vermezseniz ilk değeri 0 olarak kabul ettiğini unutmayın. range() fonksiyonu ile ilgili bilmeniz gerek diğer önemli bilgi ise 3. bir parametre alıyor olmasıdır.
range(ilk_sayı, son_sayı, atlama_değeri)
Örneği inceleyip pekiştirelim
for i in range(0, 10, 2):
    print(i)
Bu örnek üçüncü parametreyide içerdiğinden ekran çıktısı 0 dan başlayıp 2 şer artarak yazdıracaktır. Range fonksiyonu ile tersten başlayarak sayı yazdırmak istersek üçüncü parametre -1 olarak belirtilmelidir.

pass Deyimi

geçmek, pas geçmek anlamındadır. Python'da görmezden gel olarak kullanılmaktadır.
while True:
    sayı = int(input("Bir sayı girin: "))
    if sayı == 0:
        break
    elif sayı < 0:
        pass
    else:
        print(sayı)
Eğer kullanıcı 0 değerini girerse program break deyiminden dolayı sonlanır. Eğer kullanıcı eksi değerli bir sayı girerse programımız pass deyiminden dolayı görmezden gelir ve devam eder. Bunun dışında programımız girilen sayıyı ekrana yazdıracaktır.
Diyelim ki bir program geliştiriyorsunuz ve bir yerde takıldınız veya o kısımla ilgili yapılması gerekeni daha düşünmediniz bu gibi hallerde pass deyimini kullanabiliriz.
break Deyimi
Devam eden bir süreci kesintiye uğratmak için kullanılır. Örnek olarak for döngüsünün hemen üsttündeki örneği inceleyiniz.

continue Deyimi

İngilizce bir ifade olan continue devam ettirmek, sürdürmek anlamındadır.
while True:
    s = input("Bir sayı girin: ")
    if s == "iptal":
        break
    if len(s) <= 2:
        continue
    print("En fazla iki haneli bir sayı girebilirsiniz.")
Cıktı:
Bir sayı girin: 1
Bir sayı girin: 133
En fazla iki haneli bir sayı girebilirsiniz.
Bir sayı girin:
Kullanıcı 2 haneli bir sayı girerse kodlar çalışmaya devam ediyor fakat 3 haneli bir sayı girdiğimizde hemen uyarı gönderip döngünün başına geri gidiyor.