Python ile Aykırı Değer Tespiti: Pandas ve Scikit-learn Rehberi

Pandas 3.0 ve scikit-learn 1.8 ile Python'da aykırı değer tespiti: IQR, Z-skoru, Modified Z-Score, Isolation Forest, LOF ve DBSCAN yöntemlerini çalıştırılabilir kod örnekleriyle adım adım uygulayın.

Veri biliminde karşılaşacağınız en sinsi sorunlardan biri aykırı değerlerdir. Şöyle düşünün: verinin geri kalanından belirgin şekilde sapan bu noktalar, ortalamalarınızı çarpıtabilir, modellerinizi yanıltabilir ve sonuçlarınızı tamamen güvenilmez hale getirebilir. Ama işin ilginç tarafı şu — her aykırı değer kötü değildir. Bazen bir dolandırıcılık işlemini, bir sensör arızasını ya da gerçekten olağandışı bir müşteri davranışını temsil edebilir.

Ben de kendi projelerimde bunu defalarca yaşadım: modelin performansı bir türlü iyileşmiyor, saatler harcıyorsunuz, sonra bakıyorsunuz ki birkaç aykırı değer her şeyi mahvetmiş.

Bu rehberde Pandas 3.0 ve scikit-learn 1.8 kullanarak aykırı değer tespitinin A'dan Z'ye her adımını ele alacağız. Basit istatistiksel yöntemlerden makine öğrenmesi tabanlı algoritmalara kadar tüm yaklaşımları çalıştırılabilir kod örnekleriyle göstereceğiz. Hazırsanız başlayalım.

Aykırı Değer Nedir ve Neden Önemlidir?

Aykırı değer (outlier), veri setindeki diğer gözlemlerden istatistiksel olarak anlamlı ölçüde farklı olan veri noktasıdır. Somut bir örnek vereyim: bir e-ticaret veri setinde ortalama sipariş tutarı 150 TL iken 45.000 TL'lik bir sipariş, ya da bir sıcaklık veri setinde 25°C ortalamasına karşı -40°C'lik bir ölçüm. Bunlar klasik aykırı değer örnekleridir.

Peki neden bu kadar önemli?

  • İstatistiksel yanılsama: Aykırı değerler ortalama ve standart sapma gibi ölçüleri ciddi şekilde çarpıtır. Tek bir aşırı değer, tüm veri setinin ortalamasını kaydırabilir.
  • Model performansı: Lineer regresyon, K-Means gibi algoritmalar aykırı değerlere karşı oldukça hassastır. Eğitim setindeki aykırı değerler modelin genelleme kapasitesini düşürür.
  • İş kararları: Yanlış raporlamaya yol açabilir — satış ortalaması gerçekte 150 TL iken aykırı değerler yüzünden 300 TL olarak hesaplanabilir. Bu da yönetimin tamamen yanlış kararlar almasına neden olur.
  • Anomali tespiti: Bazı durumlarda aykırı değerler tam da aradığınız şeydir — dolandırıcılık, sistem arızası veya olağandışı müşteri davranışı gibi.

Çalışma Ortamının Kurulumu

Güncel kütüphane sürümleriyle çalışacağız. Pandas 3.0'ın gelişmiş vektörel işlemleri ve scikit-learn 1.8'in optimize edilmiş anomali tespit algoritmaları bu rehberin temelini oluşturuyor. Kurulum oldukça basit:

# Kütüphaneleri yükleyin
pip install pandas==3.0.1 scikit-learn==1.8.0 numpy matplotlib seaborn scipy

# Gerekli import'lar
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import RobustScaler, StandardScaler
from sklearn.pipeline import Pipeline
import warnings
warnings.filterwarnings("ignore")

Örnek Veri Seti Oluşturma

Gerçekçi bir senaryo üzerinde çalışmak her zaman daha öğreticidir. Bir e-ticaret müşteri veri seti oluşturalım ve bilinçli olarak farklı türde aykırı değerler ekleyelim. Böylece her yöntemin nasıl tepki verdiğini net şekilde gözlemleyebilirsiniz.

np.random.seed(42)
n = 1000

# Normal veri
df = pd.DataFrame({
    "musteri_id": range(1, n + 1),
    "yas": np.random.normal(35, 8, n).clip(18, 70).astype(int),
    "yillik_gelir": np.random.normal(85000, 25000, n).clip(20000),
    "aylik_harcama": np.random.normal(3500, 1200, n).clip(200),
    "siparis_sayisi": np.random.poisson(12, n),
    "iade_orani": np.random.beta(2, 10, n),
    "site_suresi_dk": np.random.exponential(15, n),
})

# Bilinçli aykırı değerler ekleyelim
# Tip 1: Aşırı yüksek gelir (zengin müşteriler)
df.loc[np.random.choice(n, 8, replace=False), "yillik_gelir"] = \
    np.random.uniform(500000, 1200000, 8)

# Tip 2: Anormal harcama kalıpları
df.loc[np.random.choice(n, 5, replace=False), "aylik_harcama"] = \
    np.random.uniform(25000, 50000, 5)

# Tip 3: Şüpheli iade oranları (olası dolandırıcılık)
df.loc[np.random.choice(n, 6, replace=False), "iade_orani"] = \
    np.random.uniform(0.8, 1.0, 6)

# Tip 4: Aşırı site süresi (bot aktivitesi?)
df.loc[np.random.choice(n, 4, replace=False), "site_suresi_dk"] = \
    np.random.uniform(300, 600, 4)

print(df.describe().round(2))
print(f"\nVeri seti boyutu: {df.shape}")

Tek Değişkenli (Univariate) Aykırı Değer Tespiti

Tek değişkenli yöntemler, her sütunu bağımsız olarak analiz eder. Basit ama etkili bir başlangıç noktasıdır. Karmaşık yöntemlere geçmeden önce mutlaka bu adımı uygulayın — inanın bana, çoğu zaman burada bile ciddi şeyler yakalarsınız.

IQR (Çeyrekler Arası Fark) Yöntemi

IQR yöntemi, verinin normal dağılıma uymasını gerektirmez ve bu onu pratikte en güvenilir tek değişkenli yöntemlerden biri yapar. Çarpık verilerle çalışırken Z-skoruna göre çok daha sağlam sonuçlar verir. Açıkçası, ben hemen hemen her projede ilk buna başvururum.

def iqr_aykiri_tespit(df, sutun, carpan=1.5):
    """IQR yöntemiyle aykırı değerleri tespit eder."""
    Q1 = df[sutun].quantile(0.25)
    Q3 = df[sutun].quantile(0.75)
    IQR = Q3 - Q1
    alt_sinir = Q1 - carpan * IQR
    ust_sinir = Q3 + carpan * IQR

    aykiri_mask = (df[sutun] < alt_sinir) | (df[sutun] > ust_sinir)

    print(f"--- {sutun} ---")
    print(f"Q1: {Q1:.2f}, Q3: {Q3:.2f}, IQR: {IQR:.2f}")
    print(f"Alt sınır: {alt_sinir:.2f}, Üst sınır: {ust_sinir:.2f}")
    print(f"Aykırı değer sayısı: {aykiri_mask.sum()} "
          f"(%{aykiri_mask.mean()*100:.1f})")

    return aykiri_mask

# Her sayısal sütun için uygulayalım
sayisal_sutunlar = ["yillik_gelir", "aylik_harcama",
                    "iade_orani", "site_suresi_dk"]

aykiri_sonuclar = {}
for sutun in sayisal_sutunlar:
    aykiri_sonuclar[sutun] = iqr_aykiri_tespit(df, sutun)
    print()

Z-Skoru Yöntemi

Z-skoru, bir veri noktasının ortalamadan kaç standart sapma uzaklıkta olduğunu ölçer. Genellikle |Z| > 3 eşik olarak kabul edilir, ancak bu eşik veri setinize göre ayarlanabilir. Kullanımı basit ama bir uyarı var — birazdan bahsedeceğim.

def zscore_aykiri_tespit(df, sutun, esik=3):
    """Z-skoru ile aykırı değerleri tespit eder."""
    z_skorlari = np.abs(stats.zscore(df[sutun].dropna()))
    aykiri_mask = pd.Series(False, index=df.index)
    gecerli_idx = df[sutun].dropna().index
    aykiri_mask.loc[gecerli_idx] = z_skorlari > esik

    print(f"--- {sutun} (Z-skoru, eşik={esik}) ---")
    print(f"Aykırı değer sayısı: {aykiri_mask.sum()}")
    print(f"Max Z-skoru: {z_skorlari.max():.2f}")

    return aykiri_mask

# Z-skoru ile tespit
for sutun in sayisal_sutunlar:
    zscore_aykiri_tespit(df, sutun)
    print()

Dikkat: Z-skoru, verinin normal dağılıma yakın olduğunu varsayar. Çarpık verilerle çalışıyorsanız (gelir, harcama gibi — ki gerçek dünyada bunlar neredeyse her zaman çarpıktır), IQR veya aşağıdaki Modified Z-Score yöntemi çok daha uygun olacaktır.

Modified Z-Score (MAD Tabanlı)

İşte benim favorilerimden biri. Median Absolute Deviation (MAD) tabanlı Modified Z-Score, aykırı değerlerin kendisine karşı dayanıklıdır — çünkü ortalama yerine medyan kullanır. Bu, onu özellikle gerçek dünya verilerinde çok değerli kılar.

def modified_zscore_tespit(df, sutun, esik=3.5):
    """MAD tabanlı Modified Z-Score ile aykırı değer tespiti."""
    medyan = df[sutun].median()
    mad = np.median(np.abs(df[sutun] - medyan))
    # MAD sıfırsa (çok az varyans), küçük bir değer ekle
    mad = mad if mad != 0 else 1e-6
    modified_z = 0.6745 * (df[sutun] - medyan) / mad

    aykiri_mask = np.abs(modified_z) > esik

    print(f"--- {sutun} (Modified Z-Score, eşik={esik}) ---")
    print(f"Medyan: {medyan:.2f}, MAD: {mad:.4f}")
    print(f"Aykırı değer sayısı: {aykiri_mask.sum()}")

    return aykiri_mask

for sutun in sayisal_sutunlar:
    modified_zscore_tespit(df, sutun)
    print()

Görselleştirme ile Aykırı Değer Analizi

Sayılar tek başına yeterli değildir. Aykırı değerleri gözle görmek, verinin dağılımını anlamak açısından kritik önem taşır. Ciddiyim — bir box plot çizmeden aykırı değer kararı vermeyin. Matplotlib ve Seaborn ile etkili görselleştirmeler oluşturalım.

Box Plot (Kutu Grafiği)

Box plot, IQR yönteminin görsel karşılığıdır. Bıyıkların dışında kalan noktalar aykırı değerleri temsil eder ve hangi değerlerin sorunlu olduğunu bir bakışta görebilirsiniz.

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("Aykırı Değer Analizi - Box Plot", fontsize=16)

for ax, sutun in zip(axes.flatten(), sayisal_sutunlar):
    sns.boxplot(data=df, y=sutun, ax=ax, color="#3498db",
                flierprops={"marker": "o", "markerfacecolor": "red",
                            "markersize": 6})
    ax.set_title(f"{sutun}", fontsize=12)
    ax.set_ylabel("")

plt.tight_layout()
plt.savefig("boxplot_aykiri.png", dpi=150, bbox_inches="tight")
plt.show()

Violin Plot ile Dağılım Analizi

Violin plot, box plot'a kıyasla verinin yoğunluk dağılımını da gösterir. Çok modlu (multimodal) dağılımlarda aykırı değerlerin bağlamını anlamak için gerçekten kullanışlı bir araçtır.

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Gelir dağılımı
sns.violinplot(data=df, y="yillik_gelir", ax=axes[0],
               color="#2ecc71", inner="box")
axes[0].set_title("Yıllık Gelir Dağılımı")

# Harcama dağılımı
sns.violinplot(data=df, y="aylik_harcama", ax=axes[1],
               color="#e74c3c", inner="box")
axes[1].set_title("Aylık Harcama Dağılımı")

plt.tight_layout()
plt.show()

Scatter Plot ile Çok Değişkenli Görselleştirme

İki değişken arasındaki ilişkiyi ve aykırı değerlerin konumunu görmek için scatter plot ideal bir tercih. Özellikle gelir-harcama gibi ilişkili değişkenlerde çok aydınlatıcı oluyor.

# Gelir vs Harcama scatter plot
iqr_mask = iqr_aykiri_tespit(df, "yillik_gelir") | \
           iqr_aykiri_tespit(df, "aylik_harcama")

fig, ax = plt.subplots(figsize=(10, 7))
normal = df[~iqr_mask]
aykiri = df[iqr_mask]

ax.scatter(normal["yillik_gelir"], normal["aylik_harcama"],
           alpha=0.5, label="Normal", color="#3498db", s=20)
ax.scatter(aykiri["yillik_gelir"], aykiri["aylik_harcama"],
           alpha=0.8, label="Aykırı", color="#e74c3c", s=60,
           edgecolors="black", linewidth=1)

ax.set_xlabel("Yıllık Gelir (TL)")
ax.set_ylabel("Aylık Harcama (TL)")
ax.set_title("Gelir vs Harcama — Aykırı Değer Haritası")
ax.legend()
plt.tight_layout()
plt.show()

Çok Değişkenli (Multivariate) Aykırı Değer Tespiti

Tek değişkenli yöntemler faydalıdır, ama gerçek dünyada aykırı değerler genellikle birden fazla değişkenin birleşiminde ortaya çıkar. Bir müşterinin geliri normal, harcaması da normal olabilir — ama gelir-harcama oranı tamamen anormal olabilir. İşte burada çok değişkenli yöntemler devreye girer ve işler ciddi anlamda ilginçleşir.

Isolation Forest

Isolation Forest, aykırı değerlerin normal veriye kıyasla daha kolay "izole edilebildiği" prensibine dayanır. Mantık şu: rastgele bölmelerle oluşturulan karar ağaçlarında, aykırı değerler daha kısa yol uzunluğuna sahip olur çünkü onları ayırmak daha kolaydır. Yüksek boyutlu verilerle çalışırken en etkili yöntemlerden biridir.

# Özellikleri hazırlayın
ozellikler = ["yillik_gelir", "aylik_harcama",
              "siparis_sayisi", "iade_orani", "site_suresi_dk"]
X = df[ozellikler].copy()

# RobustScaler ile ölçeklendirme (aykırı değerlere dayanıklı)
scaler = RobustScaler()
X_scaled = scaler.fit_transform(X)

# Isolation Forest modeli
iso_forest = IsolationForest(
    contamination=0.05,   # Verinin %5'i aykırı olarak bekleniyor
    n_estimators=200,     # Ağaç sayısı
    max_samples="auto",   # Her ağaç için örnek sayısı
    random_state=42
)

df["iso_forest_label"] = iso_forest.fit_predict(X_scaled)
df["iso_forest_skor"] = iso_forest.decision_function(X_scaled)

# Sonuçları inceleyelim
print("Isolation Forest Sonuçları:")
print(f"Normal: {(df['iso_forest_label'] == 1).sum()}")
print(f"Aykırı: {(df['iso_forest_label'] == -1).sum()}")
print(f"\nAykırı değerlerin istatistikleri:")
print(df[df["iso_forest_label"] == -1][ozellikler].describe().round(2))

Local Outlier Factor (LOF)

LOF biraz farklı bir yaklaşım izler. Her noktanın yerel yoğunluğunu komşularıyla karşılaştırır. Bir nokta, komşularına kıyasla belirgin şekilde düşük yoğunluklu bir bölgedeyse aykırı olarak işaretlenir. Farklı yoğunluktaki kümeler içeren veriler için Isolation Forest'a göre daha başarılıdır — bu önemli bir ayrım.

# Local Outlier Factor
lof = LocalOutlierFactor(
    n_neighbors=20,        # Komşu sayısı
    contamination=0.05,    # Beklenen aykırı oranı
    metric="euclidean"
)

df["lof_label"] = lof.fit_predict(X_scaled)
df["lof_skor"] = lof.negative_outlier_factor_

print("LOF Sonuçları:")
print(f"Normal: {(df['lof_label'] == 1).sum()}")
print(f"Aykırı: {(df['lof_label'] == -1).sum()}")

# LOF skorlarının dağılımını görselleştirelim
fig, ax = plt.subplots(figsize=(10, 5))
ax.hist(df["lof_skor"], bins=50, edgecolor="black", alpha=0.7)
ax.axvline(x=-1.5, color="red", linestyle="--", label="Eşik (-1.5)")
ax.set_xlabel("LOF Skoru")
ax.set_ylabel("Frekans")
ax.set_title("LOF Skor Dağılımı")
ax.legend()
plt.tight_layout()
plt.show()

DBSCAN ile Kümeleme Tabanlı Tespit

DBSCAN, yoğunluk tabanlı bir kümeleme algoritmasıdır ve burada güzel bir avantajı var: hiçbir kümeye atanamayan noktaları "gürültü" (noise) olarak etiketler — ve bu noktalar doğal olarak aykırı değer adaylarıdır. Önceden küme sayısı belirlemenize de gerek yoktur, bu da K-Means'e göre büyük bir artı.

# DBSCAN ile aykırı değer tespiti
dbscan = DBSCAN(
    eps=1.5,              # Komşuluk yarıçapı
    min_samples=10,       # Küme oluşturmak için minimum nokta
    metric="euclidean"
)

df["dbscan_label"] = dbscan.fit_predict(X_scaled)

# -1 etiketli noktalar gürültü (aykırı değer)
gurultu_sayisi = (df["dbscan_label"] == -1).sum()
kume_sayisi = df["dbscan_label"].nunique() - (1 if gurultu_sayisi > 0 else 0)

print(f"Küme sayısı: {kume_sayisi}")
print(f"Gürültü (aykırı) noktalar: {gurultu_sayisi}")
print(f"Küme dağılımı:\n{df['dbscan_label'].value_counts().sort_index()}")

Yöntemleri Karşılaştırma ve Birleştirme

Tek bir yöntem her zaman yeterli olmaz — bunu kendi deneyimimle söylüyorum. En güvenilir strateji, birden fazla yöntemi birleştirmek ve "oybirliği" yaklaşımını uygulamaktır. Yani bir noktanın aykırı olarak kabul edilmesi için birden fazla yöntemin onu işaretlemesi gerekir. Bu yaklaşım yanlış pozitif oranını ciddi şekilde düşürür.

# Tüm yöntemlerin sonuçlarını birleştir
df["iqr_aykiri"] = False
for sutun in ozellikler:
    Q1 = df[sutun].quantile(0.25)
    Q3 = df[sutun].quantile(0.75)
    IQR = Q3 - Q1
    df["iqr_aykiri"] |= (df[sutun] < Q1 - 1.5*IQR) | \
                         (df[sutun] > Q3 + 1.5*IQR)

# Oy sistemi: kaç yöntem bu noktayı aykırı olarak işaretledi?
df["aykiri_oy"] = (
    df["iqr_aykiri"].astype(int) +
    (df["iso_forest_label"] == -1).astype(int) +
    (df["lof_label"] == -1).astype(int) +
    (df["dbscan_label"] == -1).astype(int)
)

print("Oy dağılımı:")
print(df["aykiri_oy"].value_counts().sort_index())
print(f"\nEn az 3 yöntemin uzlaştığı aykırı değerler: "
      f"{(df['aykiri_oy'] >= 3).sum()}")

# Güçlü aykırı değerleri inceleyelim
guclu_aykiri = df[df["aykiri_oy"] >= 3][
    ["musteri_id"] + ozellikler + ["aykiri_oy"]
]
print("\nGüçlü aykırı değerler:")
print(guclu_aykiri.to_string(index=False))

Aykırı Değerlerle Başa Çıkma Stratejileri

Aykırı değerleri tespit ettikten sonra ne yapacağınız, kullanım senaryonuza bağlıdır. Hemen silmeye kalkışmayın — önce neden orada olduğunu anlayın. İşte en yaygın yaklaşımlar ve ne zaman hangisini kullanmanız gerektiği:

1. Kırpma (Clipping / Winsorizing)

Aykırı değerleri belirli bir aralığa sıkıştırır. Veri kaybetmek istemediğinizde idealdir ve çoğu durumda benim ilk tercihimdir.

def winsorize_sutun(seri, alt_yuzde=0.01, ust_yuzde=0.99):
    """Veriyi belirtilen yüzdelik dilim sınırlarına kırpar."""
    alt = seri.quantile(alt_yuzde)
    ust = seri.quantile(ust_yuzde)
    return seri.clip(lower=alt, upper=ust)

# Gelir sütununu kırpma
df["gelir_kirpilmis"] = winsorize_sutun(df["yillik_gelir"])
print(f"Orijinal max: {df['yillik_gelir'].max():,.0f} TL")
print(f"Kırpılmış max: {df['gelir_kirpilmis'].max():,.0f} TL")

2. Dönüştürme (Transformation)

Logaritmik veya kare kök dönüşümü ile aykırı değerlerin etkisini azaltabilirsiniz. Verinin şeklini değiştirir ama bilgiyi korur. Özellikle gelir ve harcama gibi sağa çarpık dağılımlarda harika sonuç verir.

# Log dönüşümü
df["gelir_log"] = np.log1p(df["yillik_gelir"])
df["harcama_log"] = np.log1p(df["aylik_harcama"])

print(f"Gelir çarpıklığı — Orijinal: {df['yillik_gelir'].skew():.3f}")
print(f"Gelir çarpıklığı — Log: {df['gelir_log'].skew():.3f}")

3. Silme (Removal)

Yalnızca aykırı değerin bir veri hatası olduğundan eminseniz uygulayın. Birden fazla yöntemin uzlaştığı güçlü aykırı değerleri silmek daha güvenlidir. Ama dikkatli olun — gerçek gözlemleri silmek modelinize zarar verebilir.

# Güçlü aykırı değerleri sil (en az 3 yöntem uzlaştıysa)
df_temiz = df[df["aykiri_oy"] < 3].copy()
print(f"Orijinal veri: {len(df)} satır")
print(f"Temizlenmiş veri: {len(df_temiz)} satır")
print(f"Silinen: {len(df) - len(df_temiz)} satır "
      f"(%{(len(df)-len(df_temiz))/len(df)*100:.1f})")

4. İşaretleme (Flagging)

Silmek yerine bir bayrak sütunu ekleyebilirsiniz. Bu yaklaşımı özellikle seviyorum çünkü hem veriyi korursunuz hem de model eğitiminde bu bayrak ek bir özellik olarak kullanılabilir.

# Aykırı değer bayrağı ekle
df["aykiri_bayrak"] = (df["aykiri_oy"] >= 2).astype(int)
print(f"İşaretlenen aykırı değerler: {df['aykiri_bayrak'].sum()}")

Scikit-learn Pipeline ile Aykırı Değer Tespiti

Üretim ortamında aykırı değer tespitini bir pipeline'a entegre etmek, tekrarlanabilirlik ve tutarlılık açısından kritik önem taşır. Scikit-learn'ün Pipeline yapısı bu iş için biçilmiş kaftan.

from sklearn.base import BaseEstimator, TransformerMixin

class AykiriDegerFiltresi(BaseEstimator, TransformerMixin):
    """Özel transformer: IQR tabanlı aykırı değer tespiti ve kırpma."""

    def __init__(self, carpan=1.5):
        self.carpan = carpan

    def fit(self, X, y=None):
        X_df = pd.DataFrame(X)
        self.Q1_ = X_df.quantile(0.25)
        self.Q3_ = X_df.quantile(0.75)
        self.IQR_ = self.Q3_ - self.Q1_
        self.alt_sinir_ = self.Q1_ - self.carpan * self.IQR_
        self.ust_sinir_ = self.Q3_ + self.carpan * self.IQR_
        return self

    def transform(self, X, y=None):
        X_df = pd.DataFrame(X)
        return X_df.clip(
            lower=self.alt_sinir_, upper=self.ust_sinir_, axis=1
        ).values

# Pipeline oluşturma
pipeline = Pipeline([
    ("aykiri_filtre", AykiriDegerFiltresi(carpan=1.5)),
    ("olceklendirme", RobustScaler()),
    ("anomali_tespit", IsolationForest(
        contamination=0.05, n_estimators=200, random_state=42
    ))
])

# Pipeline'ı çalıştır
X_ozellikler = df[ozellikler].values
tahminler = pipeline.fit_predict(X_ozellikler)
print(f"Pipeline sonucu — Aykırı: {(tahminler == -1).sum()}, "
      f"Normal: {(tahminler == 1).sum()}")

Hangi Yöntemi Ne Zaman Kullanmalı?

Doğru yöntemi seçmek, verinin yapısına ve amacınıza bağlıdır. İşte pratik bir karar rehberi:

  • IQR Yöntemi: Hızlı keşifsel analiz, çarpık veriler, dağılım varsayımı olmadan çalışmak istediğinizde. En güvenli başlangıç noktası — şüphedeyseniz bununla başlayın.
  • Z-Skoru: Normal dağılıma yakın veriler ve istatistiksel test gerektiren senaryolar. Çarpık verilerde yanıltıcı olabileceğini unutmayın.
  • Modified Z-Score (MAD): Aykırı değerlerin kendisinin analizi etkileyebileceği durumlar. Z-skorunun dayanıklı versiyonu diyebiliriz.
  • Isolation Forest: Yüksek boyutlu veriler, büyük veri setleri, otomatik tespit gerektiren senaryolar. Ölçeklenebilir ve hızlı.
  • LOF: Farklı yoğunluktaki kümeler içeren veriler, yerel anomalilerin önemli olduğu durumlar.
  • DBSCAN: Kümeleme ve aykırı değer tespitini aynı anda yapmak istediğinizde. Parametre ayarlaması biraz hassas olabilir ama doğru ayarlandığında çok güçlü.

Sık Sorulan Sorular (FAQ)

Aykırı değerleri silmek mi yoksa dönüştürmek mi daha iyi?

Bu tamamen bağlamınıza bağlıdır. Aykırı değer bir veri hatası ise (yanlış giriş, sensör arızası) silmek doğrudur. Ancak gerçek bir gözlemse (örneğin zengin bir müşteri) silmek bilgi kaybına yol açar — bu durumda kırpma veya log dönüşümü tercih edin. Genel kural olarak: emin değilseniz silmeyin, dönüştürün.

Isolation Forest ve LOF arasındaki fark nedir?

Isolation Forest, global bir yaklaşım kullanarak aykırı değerleri rastgele bölmelerle izole eder ve yüksek boyutlu veriler ile büyük veri setleri için idealdir. LOF ise yerel yoğunluk karşılaştırması yapar; bu sayede farklı yoğunluklardaki kümelerde de aykırı değerleri doğru tespit edebilir. Kısaca: küçük-orta ölçekli ve karmaşık yoğunluk yapısına sahip verilerde LOF, büyük ölçekli verilerde Isolation Forest tercih edilir.

Aykırı değer tespitinde contamination parametresini nasıl belirlemeliyim?

Alan bilginiz varsa beklenen aykırı oranını doğrudan belirleyebilirsiniz. Bilmiyorsanız, scikit-learn'ün varsayılan "auto" değeriyle başlayın. Alternatif olarak, farklı contamination değerleriyle deneyin ve sonuçları görsel olarak doğrulayın. Çoğu gerçek dünya veri setinde %1-5 aralığı iyi bir başlangıç noktasıdır.

Ağaç tabanlı modeller (XGBoost, Random Forest) için aykırı değer temizliği gerekli mi?

Ağaç tabanlı modeller, veriyi bölme noktalarına göre ayırdığından aykırı değerlere karşı doğal olarak dayanıklıdır. Bu yüzden lineer regresyon veya K-Means gibi mesafe tabanlı algoritmalara kıyasla aykırı değer temizliği daha az kritiktir. Yine de aşırı uç değerler ağaç bölmelerini etkileyebilir — özellikle küçük veri setlerinde dikkatli olun.

Zaman serisi verilerinde aykırı değer tespiti nasıl farklılık gösterir?

Zaman serisi verilerinde aykırı değerler, trendin ve mevsimselliğin dışında kalan noktalar olarak tanımlanır. Standart IQR veya Z-skoru yöntemleri doğrudan uygulanamaz çünkü verinin zamansal yapısını göz ardı ederler. Bunun yerine hareketli ortalama penceresi, STL decomposition sonrası artıkları analiz etme veya Prophet gibi zaman serisi modellerinin tahmin aralıklarını kullanma gibi yöntemler tercih edilmelidir.

Yazar Hakkında Editorial Team

Our team of expert writers and editors.