Veri Biliminde Normal Dağılmayan Verilerin Dönüştürülme (Transformation) Yöntemleri Logaritmik, Box-Cox, Karekök, Reciprocal

Yiğit Şener
Data Runner
Published in
6 min readOct 1, 2020

İstatistikte ve dolayısıyla veri biliminde parametrik testlerin uygulanabilirliği için normal dağılım varsayımı önemlidir. Bir değişkenin normal dağılım göstermemesi durumunda çeşitli veri dönüştürme (transformation) teknikleri bulunmaktadır. Bu yöntemler ile değişkenin dağılımını normale yaklaştırmak mümkün hale gelebilmektedir.

Bu yazı, normal dağılıma dair oluşturulan serinin devamı olarak ele alınmıştır. Serinin diğer yazılarına aşağıdaki konu başlıklarından ulaşabilirsiniz.

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ğıdaki örnek veri setini, serinin diğer yazılarında normal dağılım testleri ve grafikler ile incelemiştik. Bazı değişkenlerin çarpıklık düzeyinin yüksek olmasından dolayı normal dağılmadığını görebilmiştik. Şimdi aynı veri setinde normal dağılmayan değişkenleri yeniden bulalım. Öncelikle veri setine Python üzerinden erişip Scipy kütüphanesi ile Shapiro-Wilk testimizi yapalım. Aşağıdaki kodları kullanarak veriyi alamıyorsanız bu adres üzerinden indirebilirsiniz.

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

# 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" : "ingilizce",
"History" : "Tarih"})

# shapiro-wilk normallik testi
for i in df.columns:
_, p = stats.shapiro(df[i])
print(f"{i}: {round(p,4)}")

# ÇIKTI:
# Matematik: 0.5503
# ingilizce: 0.0
# Tarih: 0.0001

Yukarıdaki for döngüsünden çıkan Shapiro-Wilk normallik testi sonucuna göre İngilizce ve Tarih derslerinin (p < 0.05) normal dağılmadığı görülmektedir. İngilizce dersi için histograma bakalım.

# Tarih değişkenin sıralanıp
# tek değişkene tanıtılması
tarih = df.Tarih.sort_values()

# dağılım eğrisi
mean, std = stats.norm.fit(tarih, loc=0)
pdf_norm = stats.norm.pdf(tarih, mean, std)

# Histogram ve dağılım eğrisi
plt.hist(tarih, bins='auto', density = True
,color = "grey", ec="skyblue")
plt.plot(tarih, pdf_norm, label='Dağılım Eğrisi'
,color = "red", linewidth=4, linestyle=':')
plt.legend()
plt.show()

Histogramda görüldüğü üzere Tarih dersine ait veriler çarpık (skew) olarak dağılmaktadır. Değişkeni daha normal bir dağılıma dönüştürmek için aşağıdaki teknikleri uygulayabiliriz.

Logaritmik Dönüşüm (Log Transformation)

Log dönüşümünde, x’in her değeri log (x) ile 10 tabanı, 2 tabanı veya doğal log ile değiştirilebilir.

# Orjinal değişken
tarih = df.Tarih.sort_values()
# dağılım eğrisi
mean, std = stats.norm.fit(tarih, loc=0)
pdf_norm = stats.norm.pdf(tarih, mean, std)

# logaritmik dağılım eğrisi
shape, loc, scale = stats.lognorm.fit(tarih, loc=0)
pdf_lognorm = stats.lognorm.pdf(tarih, shape, loc, scale)

# Grafikler
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))

# Orjinal veriler ve dağılımı
ax1.hist(tarih, bins= 20 , density=True
,color = "grey", ec= "skyblue")

ax1.plot(tarih, pdf_norm
,color = "red", linewidth=4, linestyle=':')

ax1.set_ylabel('Olasılık')
ax1.set_title('Orjinal Boyut')

# Orjinal dağılıma göre log dönüşüm
ax2.hist(tarih, bins= 20, density=True
,color = "green", ec="skyblue")

ax2.plot(tarih, pdf_lognorm
,color = "red", linewidth=4, linestyle=':')

ax2.set_xscale('log')
ax2.set_title('Logaritmik Dönüşüm')
plt.show()

Yukarıdaki grafikler orijinal ve Logaritmik dönüşüm verilerinin karşılaştırılmasını göstermektedir. Burada, dönüştürülen verilerde çarpıklığın azaldığını görüyoruz (en iyi çarpıklık değeri sıfıra yakın olmalıdır).

Karekök Dönüşümü (Square-Root Transformation)

Bu dönüşüm, dağıtım üzerinde ılımlı bir etki sağlamaktadır. Karekök dönüşümünün temel avantajı sıfır değerlerine uygulanabilmesidir.
Burada X değeri için, karekök (X) ile değiştirilir. Logaritmik dönüşüme göre daha zayıf bir etkisi bulunmaktadır.

# Orjinal değişken
tarih = df.Tarih.sort_values()

# karakök alınmış hali
tarih_sr = tarih ** (1/2)

# orjinal dağılım eğrisi
mean, std = stats.norm.fit(tarih, loc=0)
pdf_norm = stats.norm.pdf(tarih, mean, std)

# orjinal dağılım eğrisi
mean, std = stats.norm.fit(tarih_sr, loc=0)
pdf_norm_sk = stats.norm.pdf(tarih_sr, mean, std)


# Grafikler
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))

# Orjinal veriler ve dağılımı
ax1.hist(tarih, bins= 20 , density=True
,color = "grey", ec= "skyblue")

ax1.plot(tarih, pdf_norm
,color = "red", linewidth=4, linestyle=':')

ax1.set_ylabel('Olasılık')
ax1.set_title('Orjinal Boyut')

# karakök dönüşüm grafiği
ax2.hist(tarih_sr, bins= 20, density=True
,color = "green", ec="skyblue")

ax2.plot(tarih_sr, pdf_norm_sk
,color = "red", linewidth=4, linestyle=':')

ax2.set_title('Karakök Dönüşüm')
plt.show()

Karşıt Dönüşüm (Reciprocal Transformation)

Bu dönüşümde X değeri için X’in tersiyle (1 / X) değiştirilecektir.
Karşılıklı dönüşüm, dağılımın şekli üzerinde çok az etki sağlayacaktır. Bu dönüşüm yalnızca sıfır olmayan değerler için kullanılabilir.

# Orjinal değişken
tarih = df.Tarih.sort_values()

# tersine döndürülmüş hali
tarih_sr = 1 / tarih

# orjinal dağılım eğrisi
mean, std = stats.norm.fit(tarih, loc=0)
pdf_norm = stats.norm.pdf(tarih, mean, std)

# orjinal dağılım eğrisi
mean, std = stats.norm.fit(tarih_sr, loc=0)
pdf_norm_sk = stats.norm.pdf(tarih_sr, mean, std)

# Grafikler
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))

# Orjinal veriler ve dağılımı
ax1.hist(tarih, bins= 20 , density=True
,color = "grey", ec= "skyblue")

ax1.plot(tarih, pdf_norm
,color = "red", linewidth=4, linestyle=':')

ax1.set_ylabel('Olasılık')
ax1.set_title('Orjinal Boyut')

# Karşıt dönüşüm grafiği
ax2.hist(tarih_sr, bins= 20, density=True
,color = "green", ec="skyblue")

ax2.plot(tarih_sr, pdf_norm_sk
,color = "red", linewidth=4, linestyle=':')

# ax2.set_xscale('Karakök')
ax2.set_title('Katşıt Dönüşüm')
plt.show()

Grafiklerde de görüldüğü üzere çokta etkili görülmeyen bir dönüşüm yöntemidir. Ancak spesifik modellerde bazı input değerler üzerinde denenebilir.

Box-Cox Dönüşümü

Box-Cox dönüşümü, çarpık veriler üzerinde oldukça düzeltici etkilesi olduğu bilinen istatistiksel bir tekniktir. Fonksiyon, normal olmayan dağılımı normal dağılıma dönüştürme türünü lambda (λ) parametresine göre belirlemektedir. Box-Cox için lambda (λ) parametresi -5 <λ <5 aralığına sahiptir. Lambanın aldığı değerler ve karşısındaki dönüşüm türü aşağıdaki gibidir.

  • lambda = -1 Karşıt (Reciprocal) Dönüşüm
  • lambda = -0.5 Karşıt Karekök Dönüşümü
  • lambda = 0.0 Logaritmik Dönüşüm
  • lambda = 0.5 Karekök Dönüşümü
  • lambda = 1.0 Dönüşüm Yok
# Orjinal değişken
tarih = df.Tarih.sort_values()

# tersine döndürülmüş hali
tarih_sr, lam = stats.boxcox(tarih)

# orjinal dağılım eğrisi
mean, std = stats.norm.fit(tarih, loc=0)
pdf_norm = stats.norm.pdf(tarih, mean, std)

# Box-Cox dağılım eğrisi
mean, std = stats.norm.fit(tarih_sr, loc=0)
pdf_norm_sk = stats.norm.pdf(tarih_sr, mean, std)

# Grafikler
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))

# Orjinal veriler ve dağılımı
ax1.hist(tarih, bins= 20 , density=True
,color = "grey", ec= "skyblue")

ax1.plot(tarih, pdf_norm
,color = "red", linewidth=4, linestyle=':')

ax1.set_ylabel('Olasılık')
ax1.set_title('Orjinal Boyut')

# Box-Cox dönüşüm grafiği
ax2.hist(tarih_sr, bins= 20, density=True
,color = "green", ec="skyblue")

ax2.plot(tarih_sr, pdf_norm_sk
,color = "red", linewidth=4, linestyle=':')

ax2.set_title('Box-Cox Dönüşüm')
plt.show()

Grafiklerden de görüleceği üzere Box-Cox yöntemine sahip olan dağılımın normalleştiği gözle görülür bir şekilde belirginleşmiştir.

Sonuç

Bu yazıda, normalliğin daha iyi uyumu için farklı dönüşüm türlerine değindik. En iyi dönüşüm tekniği diye bir görüş söz konusu değildir. Yapılan modelin biçimine, rengine, kokusuna göre farklı tipteki metotlar kullanılabilir. Ancak veri bilimi dünyasında Box-Cox dönüşüm tarzı sıklıkla kullanılmaktadır.

Diğer Yazılarım:

--

--