Veri Biliminde Normal Dağılımın Python Üzerinden Görselleştirilmesi ve Yorumlanması (Histogram, Box Plot, KDE Plot, QQ Plot ve Violin Plot)

Yiğit Şener
Data Runner
Published in
7 min readSep 17, 2020

Normal dağılıma dair yazı serisinin ikinci bölümünde artık uygulamaya geçiyoruz. Bu yazıda normal dağılımın farklı tipteki grafikler üzerinden nasıl oluşturulduğunu ve nasıl yorumlandığından bahsedeceğim.

Normal Dağılım Serisinin İçeriği:

  1. Veri Biliminde İstatistik Alanının Kalbi Olan Normal Dağılım (Gaussian Distriburion) Konusuna Genel Bir Bakış
  2. Veri Biliminde Normal Dağılımın Python Üzerinden Görselleştirilmesi ve Yorumlanması (Histogram, Box Plot, KDE Plot, QQ Plot ve Violin Plot)
  3. Veri Biliminde Normal Dağılımın R ve Python ile Testi ve Yorumlanması (Skewness ve kurtosis, Shapiro-Wilk, Kolmogorov-Smirnov)
  4. Veri Biliminde Normal Dağılmayan Verilerin Dönüştürülme (Transformation) Yöntemleri Logaritmik, Box-Cox, Karekök, Reciprocal

Aşağıda yer alan grafiklerde kullanımı için Github adresimde bulunan öğrencilerin matematik, tarih ve İngilizce ders durumlarının yer aldığı veri setini kullanacağız. Bu veri setini aşağıdaki URL bağlantı örneğinde olduğu gibi doğrudan Github’a bağlanarak alabilirsiniz. Eğer aşağıdaki kod ile veriyi çekemiyorsanız buradaki adresten de indirebilirsiniz.

Örneklere geçmeden önce veri alma, işleme, anlama ve görselleştirme için gerekli olan kütüphaneleri Python ortamında aktif hale getirip veriyi Github üzerinden alalım ve istatistiksel olarak veri setine bir bakalım.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# Veriye github üzerinden ulaşalım
url = "https://github.com/yigitsener/machine-learning/blob/master/data/lessons.csv"
df = pd.read_csv(url + "?raw=true", error_bad_lines=False)

# Kolon isimlerini değiştirme
df = df.rename(columns = {"Maths" : "Matematik",
"English" : "İngilizce",
"History" : "Tarih"})

# satır ve kolon sayısı
print(f"satır sayısı: {df.shape[0]}, kolon sayısı: {df.shape[0]}")
# ÇIKTI: satır sayısı: 100, kolon sayısı: 100

# Veri setine ait ilk 5 satır
print(df.head())
# Betimleyici İstatistikler
print(df.describe())

Yukarıdaki betimleyici istatistikten yola çıkarak aşağıdaki varsayımlara ulaşabiliriz.

  • Matematik dersi için öğrencilerin notlarının ortalaması ile medyanı (%50 yazan yer) birbirine yakın görüldüğü için en başta manidar bir normal dağılıma delalet olduğu söylenebilir. Üç standart sapma değeri (std = 8,49) için 8,49 * 3 = 25,47 için matematik notlarının dağılımı 44 (70,26 - 25,47) ile 95 (70,26 + 25,47) arasında yer almaktadır. Minimum (50) ve maksimum (89) değerleri (44 < X < 95) bu aralık içinde yer aldığından outlier olasılığından düşmektedir. Burada standart sapmada alınan değer bakılan değişkene göre farklılık gösterebilir. Örneğin bu değişken için standart sapmayı 2 alsaydık eğer maksimum değerler için outlier varsayımında bulunabilirdik.
  • İngilizce dersinin ortalama (62,56) ve medyanı (62,17) birbirine oldukça yakın görünüyor. Ancak Matematikteki 3 standart sapmayı kabul edip incelediğimizde; 1,81 * 3 = 5,43 ile normal dağılım aralığını 57 ve 67 arasında bulmaktayız. Bu durumda maksimum verilerde outlier söz konusu olabilmektedir.
  • Tarih dersini incelediğimizde ise daha geniş bir aralık (range) ile karşı karşıya olduğumuzu standart sapmanın 17 olduğundan anlayabiliriz. Bu ders içinde standart sapmayı 3 olarak kabul ettiğimizde ise minimum değerlerde bir outlier söz konusu olabilmektedir.

Şimdi farklı görselleştirme yöntemleri ile değişkenleri inceleyelim.

Histogram (Çubuk Grafik)

Histogram, hızlı ve çabuk bir şekilde bir değişkenin dağılımı hakkında fikir sahibi olunmasını sağlar. Sürekli sayısal değişken için geçerli olan histogram, sayıların belli gruplara bölünerek gösterimini sağlar. Bu yöntemin adı BINS’dir. Bins metodu kısacası frekansa göre sayısal verileri gruplara böler. Aşağıdaki ilk ve ikinci örnekte Matematik değişkeni için farklı bins kullanılarak histogram oluşturulmuştur.

BINS = 10 için histogram oluşturalım ve dağılıma göre en uygun çan eğrisini (bell curve) çizdirerek değerlendirelim.

# Histogram plot parametreleri
_, bins, _ = plt.hist(df.Matematik, bins = 10,
density = 1, alpha = 0.5,
ec= 'black' )

# Çan eğrisi için en uygun değerler
mu, sigma = stats.norm.fit(df.Matematik)
best_fit_line = stats.norm.pdf(bins, mu, sigma)

# Çan eğrisi gösterimi
plt.plot(bins, best_fit_line, 'g-o')
plt.xlabel("Not Değerleri")
plt.ylabel("Frekans")
plt.show()

Yukarıdaki histogramda görüldüğü üzere bins = 10 için 10 ayrı parçaya bölerek frekans yoğunluğunu göstermiştir. Ayrıca çağ eğrisi çizdirerek histogramın dağılımını gözlemlemek daha kolay bir hale gelmiştir.

Şimdi BINS = 25 için kodda yer alan plt.hist içindeki bins parametresine 25 atadığımızda aşağıdaki grafik ortaya çıkmaktadır.

BINS değerini artırdığımız zaman daha detayda inceleme şansına sahip oluyoruz.

İngilizce ve tarih dersleri için yukarıdaki kod için df.Matematik yerine df.ingilizce ve df.Tarih ile bins = 10 değerini yazarak aşağıdaki grafikleri elde ederiz.

Öncelikle İngilizce dersi için bakalım;

İngilizce Dersi için Histogram

Grafikte görüldüğü üzere İngilizce dersi için bir normallikten söz edemeyiz. Sağdan çarpıklık durumu (Right Skewed Distribution) görülmektedir.

Tarih dersi için histograma bakalım;

Tarih Dersi için Histogram

Tarih dersi için İngilizcede olan durumun tam tersi geçerli olup soldan bir çarpıklık (Left Skewed Distribution ) söz konusudur.

Box Plot (Kutu Grafik)

Box plot, beş rakamlı bir özete (“minimum”, birinci çeyrek (Q1), medyan, üçüncü çeyrek (Q3) ve “maksimum”) dayalı olarak verilerin dağılımını göstermenin standart bir yoludur. Box plot ile gösterilen bir değişkenin hangi özellikleri plotun neresinde mevcut olduğunu aşağıdaki şekilde görebilirsiniz.

Box Plot Bileşenleri
  • Medyan (%50 quartile): Değişkene ait verilerin ortasında yer alan değer.
  • İlk Quartile (%25): Kısacası medyan ile minimumun ortasındaki değer olarak açıklanabilir.
  • Üçüncü Quartile (%75): Medyan ile maksimumum ortasındaki değer olarak açıklanabilir.
  • interquartile range (IQR): ilk ve üçüncü quartile arasında yer alan değerler bu aralığa girmektedir.
  • Maksimum: Üçüncü quartile + IQR * 1,5 = bize maksimumdeğerini verir.
  • Minimum: İlk quartile - IQR * 1,5 = bize minimum değerini verir.
  • Outliers: Hesaplanan minimum ve maksimum değerlerin dışında kalan veriler outlier olarak nitelendirilir.

Şimdi kendi veri setimize geri dönüp box plot üzerinden her üç değişkenini de yan yana ekleyerek inceleyelim.

# 9'a 3'lük bir alan için grafik sahası oluşturuyoruz
plt.figure(figsize=(9, 3))

plt.subplot(131)
plt.boxplot(df.Matematik,)
plt.title("Matematik")

plt.subplot(132)
plt.boxplot(df.İngilizce)
plt.title("İngilizce")

plt.subplot(133)
plt.boxplot(df.Tarih)
plt.title("Tarih")

plt.show()

Box plotlarda ilk başta gözümüze çarpan matematik dersinin normal bir dağılım izlenimi vermesi. Bunun yanı sıra ingilizce ve tarih dersleri için küçük dairelerden görüldüğü şekilde aykırı (outlier) değerlerin oluştuğunu görebiliriz.

Box plot, aynı anda birden fazla değişkenin dağılımını görselleştirmek için harika bir yoldur, ancak genişlik / noktasallıktaki sapmayı bu görselleştirmeyi kullanarak belirlemek zordur.

Kernel Density Estimation (KDE)

KDE, verilerden tahmin edilen bir histogramın doğrusal anlamda düzenleştirilmiş haldir. Bu yöntemde, her bir veri noktasında sürekli bir eğri (çekirdek/kernel) çizilir ve daha sonra tüm bu eğriler, tek bir düzgün yoğunluk tahmini yapmak için birbirine eklenir.

Örnek veri setinden yola çıkarak KDE görselleştirmesini yaparak dağılıma bir bakalım. Pandas kütüphanesi içerisinde KDE grafiğini çizdirebilmekteyiz.

df.plot.kde()

KDE grafiğini incelediğimiz zaman değişkenlerin arasındaki dağılım gözlemlemek için benzer aralıklarda olmadığından dolayı üç ders için değerleri normalize edip yeniden bakalım.

# Normalizasyon fonksiyonu
def normalize(df):
result = df.copy()
for feature_name in df.columns:
max_value = df[feature_name].max()
min_value = df[feature_name].min()
result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
return result

# Değişkenleri normalize ediyoruz.
normal = normalize(df)

# KDE plotu yeniden çizdiriyoruz.
normal.plot.kde()

Tüm değişkenleri aynı ölçütte değerlendirebileceğimiz bir formata getirdiğimize göre dağılım farklılıklarını daha iyi gözlemleyebiliriz. Yine matematik için normal bir dağılım görülürken ingilizce ve tarih dersleri için bir çarpıklığın (sağa/sola yatık) olduğu görülmektedir.

QQ Plot

QQ (quantile-quantile) grafiği, verilerin normal dağılımın durumunu teorik niceliğiyle karşılaştırmanın efektif bir yoludur. Veriler merkez hatta (line) ne kadar yakınsa, verilerin yayılımı normal dağılıma o kadar yakın demektir.

Not: bu grafiğin çizimi için statsmodel kütüphanesinde yer alan qqplot metodundan yararlanılmıştır.

# 3 QQ grafiği tek alanda çizdiriyoruz
import statsmodels.api as sm
fig, (ax, ax2, ax3) = plt.subplots(ncols=3,figsize=(15, 5))

sm.qqplot(df.Matematik, line = "s", ax = ax)
ax.set_title("Matematik")

sm.qqplot(df.İngilizce, line = "s", ax = ax2)
ax2.set_title("İngilizce")

sm.qqplot(df.Tarih, line = "s", ax = ax3)
ax3.set_title("Tarih")

plt.show()

Matematik notlarına ait verilerin normal dağıldığını diğer grafiklerde zaten görmüştük. QQ grafiğinde ise bir çizgiye oturmuş olarak bu dağılımın normalliğini tekrardan görüyoruz. Aynı şekilde diğer iki ders için çizginin dışına taşan sapmalar mevcut

Violin Plot

Violin (keman) grafiği verilerin dağılımını ve olasılık yoğunluğunu görselleştirmek için en efektif yöntemlerden birisidir.

Violin grafiği box plot ve KDE’nin kombinasyonundan doğmuştur. Box plot, görsel basitliği ve verilerdeki değerlerin nasıl dağıldığına ilişkin önemli ayrıntıları gizleme eğiliminde olduğundan, değişken değerlerinin dağılımının gösterilmesinde sınırları bulunmaktadır.

Yukarıda şekilde, violin grafiğinin anatomisi yansıtılmıştır. Görüldüğü üzere hem box plotta yer alan quartile mantığını hem de KDE’de gelen yoğunlaşmayı bir arada göstererek değişkenin dağılımına yönelik oldukça fazla bilgi barındırabilmektedir.

Kullandığımız veri setindeki değişkenleri violin plot ile inceleyelim.

# 3 violin grafiği tek alanda çizdiriyoruz
fig, (ax, ax2, ax3) = plt.subplots(ncols=3,figsize=(15, 5))

ax.violinplot(df.Matematik)
ax.set_title("Matematik")

ax2.violinplot(df.İngilizce)
ax2.set_title("İngilizce")

ax3.violinplot(df.Tarih)
ax3.set_title("Tarih")

plt.show()

Yukarıdaki her bir değişken için çizdirilen violin plotlarda verilerin hangi aralığa doğru dağıldığını ve nerelerde dengesizlik olduğunu açıkça yansıtmaktadır.

Sonuç

Makine öğrenmesinde kuracağınız modelin sonucunda eğer mantıklı çıktılar elde etmek istiyorsanız değişkenlerinizin nasıl dağıldığını gözlemleyerek hareket etmeniz sizi daha başarılı sonuçlara götürecektir. Aynı zamanda bu görselleştirme yöntemleri ile derdinizi daha iyi anlatabilirsiniz.

Diğer Yazılarım:

--

--