İçeriğe geç

IQR, Tukey's Fences ve Adjusted Boxplot: Skewed Veride Outlier Tespiti

Interquartile Range (IQR), Tukey's fences (k=1.5 / k=3), boxplot anatomi, ve skewed (asimetrik) veride medcouple ile adjusted boxplot — z-score'un işe yaramadığı yerlerde robust alternatifler.

Şükrü Yusuf KAYA
22 dakikalık okuma
Başlangıç
IQR, Tukey's Fences ve Adjusted Boxplot: Skewed Veride Outlier Tespiti
📊 Quartile'lar — istatistiğin görsel dili
Boxplot 1977'de John Tukey tarafından yayımlandı. Hâlâ her veri bilimcinin ilk gördüğü grafiklerden biri. Bu derste 'boxplot çizmek'i değil, 'IQR ile sistematik outlier tespiti yapmak'ı öğreneceğiz. Üstelik klasik IQR'ın skewed (asimetrik) veride neden başarısız olduğunu ve buna çözümü (adjusted boxplot + medcouple) konuşacağız.

IQR Nedir?#

Interquartile Range — verinin orta %50'sinin kapsadığı aralık.
Tanımı:
Burada:
  • Q1 (alt çeyrek) — verinin %25'lik dilim sınırı
  • Q3 (üst çeyrek) — verinin %75'lik dilim sınırı
IQR, dağılımın yayılımını ölçer ama outlier'lara karşı çok dirençli. Bir veri kümesinin %25'i bozulsa bile IQR değişmez (sadece çeyrekler dışında kalanlar etkilenir).

Q1, Q2 (median), Q3 nasıl hesaplanır?#

data = sorted([1, 2, 3, 4, 5, 6, 7, 8, 9]) # n = 9 # Q1 = sorted[0.25 * (n-1)] = sorted[2] = 3 # Q2 = median = sorted[4] = 5 # Q3 = sorted[0.75 * (n-1)] = sorted[6] = 7 # IQR = 7 - 3 = 4
NumPy ile:
import numpy as np q1, q3 = np.percentile(data, [25, 75]) iqr = q3 - q1

Tukey's Fences: 1.5 × IQR Kuralı#

Tukey (1977) outlier'ları işaretlemek için iki sınır önerdi:

İç Sınırlar (Inner Fences) — "Mild Outliers"#

Bu sınırların dışındaki gözlemler mild outlier sayılır.

Dış Sınırlar (Outer Fences) — "Extreme Outliers"#

Bu sınırların dışındakiler extreme outlier.

k=1.5 Sihirli mi?#

Hayır. Tukey deneysel olarak seçti — normal dağılımda %0.7 false positive verir. Eğer veride beklenen outlier oranı çok düşükse (örn. %0.1) k=3 daha güvenli; daha gevşek tespit için k=1.0 da kullanılır.
k değeriFalse positive (normal)Tipik kullanım
1.0%3Agresif tespit
1.5%0.7Tukey standart
2.0%0.05Konservatif
3.0%0.0002Sadece extreme outlier
python
import numpy as np
 
def iqr_outliers(x, k=1.5):
"""
Tukey's fences ile outlier tespiti.
 
Returns: outlier indices array, ve sınırlar (low, high)
"""
q1, q3 = np.percentile(x, [25, 75])
iqr_value = q3 - q1
lower = q1 - k * iqr_value
upper = q3 + k * iqr_value
 
is_outlier = (x < lower) | (x > upper)
return np.where(is_outlier)[0], (lower, upper)
 
# Örnek
np.random.seed(42)
data = np.concatenate([
np.random.normal(50, 5, 100), # normal
[80, 85, 90, 15, 10], # outlier'lar
])
 
idx, bounds = iqr_outliers(data, k=1.5)
print(f"Outlier sayısı: {len(idx)}")
print(f"Sınırlar: ({bounds[0]:.1f}, {bounds[1]:.1f})")
print(f"Outlier değerler: {data[idx]}")
IQR-based outlier tespiti

Boxplot Anatomi#

Boxplot tüm bu çeyrek bilgisini tek bir görsele sığdırır:
┌───────────┐ │ │ <-- Q3 (üst kenar) │ │ ├───── ─────┤ <-- Q2 (median, ortadaki çizgi) │ │ │ │ └───────────┘ <-- Q1 (alt kenar) │ │ <-- whisker (Tukey upper = Q3 + 1.5*IQR'a kadar) │ ● <-- outlier (whisker dışı)
Hızlı yorum yöntemi:
  • Kutu büyük → veri yayılımı geniş
  • Kutu küçük → sıkışmış
  • Median kutunun ortasında değil → asimetrik (skewed) dağılım
  • Bir whisker uzun, diğeri kısa → asimetri var
  • Outlier noktalar → IQR fence'i dışında
python
import matplotlib.pyplot as plt
import numpy as np
 
# Üç farklı dağılım simüle et
np.random.seed(42)
normal_data = np.random.normal(50, 10, 1000)
skewed_data = np.random.exponential(scale=20, size=1000) + 30 # right-skewed
heavy_tail = np.concatenate([np.random.normal(50, 5, 950),
np.random.normal(50, 30, 50)]) # heavy tail
 
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].boxplot(normal_data, vert=True)
axes[0].set_title('Normal Dağılım')
 
axes[1].boxplot(skewed_data, vert=True)
axes[1].set_title('Sağa Skewed (exponential)')
 
axes[2].boxplot(heavy_tail, vert=True)
axes[2].set_title('Heavy-tail')
 
plt.tight_layout()
plt.savefig('reports/boxplots_comparison.png', dpi=120)
plt.show()
Üç farklı dağılım için boxplot

IQR'ın Skewed Veride Problemi#

Klasik IQR + Tukey's fences simetrik dağılım varsayar. Veri right-skewed (sağa eğik) ise — finansal tutarlar, gecikme süreleri, gelir dağılımları — klasik fence:
  • Alt sınır gereksiz dar olur → çoğu normal değer "outlier" işaretlenir
  • Üst sınır gerçek outlier'ları yakalamaz

Somut Örnek: Maaş Dağılımı#

Türkiye'de aylık net maaş right-skewed: medyan ~25.000 TL ama top-%1 milyonların üstünde. Klasik IQR:
salaries = ... # gerçek dağılım q1, q3 = 18000, 35000 iqr = 17000 upper_fence = 35000 + 1.5*17000 = 60500
60.500 TL üstündeki herkes "outlier" — ama yöneticiler, mühendisler, doktorlar zaten 80-150K TL kazanır. Bu outlier değil dağılımın doğal sağ kuyruğu.

Çözüm: Adjusted Boxplot + Medcouple#

Hubert ve Vandervieren (2008): asimetri varsa fence'i ayarla.
Medcouple asimetri (skewness) ölçüsü; -1 ile +1 arası:
Burada m = median. MC > 0 sağa skewed; MC < 0 sola skewed; MC = 0 simetrik.

Adjusted Boxplot Fences#

MC > 0 ise (right-skewed):
MC < 0 ise (left-skewed):
python
from statsmodels.stats.stattools import medcouple
 
def adjusted_boxplot_outliers(x, k=1.5):
"""
Hubert-Vandervieren adjusted boxplot.
Skewed veride klasik IQR'a göre çok daha az false positive verir.
"""
q1, q3 = np.percentile(x, [25, 75])
iqr_v = q3 - q1
mc = medcouple(x)
 
if mc >= 0:
lower = q1 - k * np.exp(-4 * mc) * iqr_v
upper = q3 + k * np.exp(3 * mc) * iqr_v
else:
lower = q1 - k * np.exp(-3 * mc) * iqr_v
upper = q3 + k * np.exp(4 * mc) * iqr_v
 
is_outlier = (x < lower) | (x > upper)
return np.where(is_outlier)[0], (lower, upper, mc)
 
# Maaş örneği
np.random.seed(42)
salaries = np.concatenate([
np.random.lognormal(mean=10, sigma=0.5, size=900), # ~22-180K TL
[400000, 500000, 800000], # gerçek outlier'lar (CEO seviyesi)
])
 
# Klasik IQR
idx_iqr, b_iqr = iqr_outliers(salaries, k=1.5)
print(f"Klasik IQR: {len(idx_iqr)} outlier")
 
# Adjusted boxplot
idx_adj, (lo, hi, mc) = adjusted_boxplot_outliers(salaries, k=1.5)
print(f"Adjusted boxplot: {len(idx_adj)} outlier (MC={mc:.3f})")
Adjusted boxplot — skewed veri için
💎 Pratik Pearl
Production'da feature'larının distribution'ına bak. Skewness > 1 ise ((|\text{MC}| > 0.3) eşdeğer), klasik IQR yerine adjusted boxplot kullan. Banking ekiplerinde bu basit değişiklik aylık ~%15 false positive azaltır.

Hangi Yöntem Ne Zaman?#

YöntemTercih edilen veriTipik kullanım
Z-ScoreNormal dağılım, az outlierHipotez testleri, klasik istatistik
Modified Z (MAD)Az kirli, normal-benzeriGenel-amaçlı robust
IQR / Tukey's fencesSimetrik veya hafif skewedEDA, dashboard
Adjusted Boxplot (medcouple)Belirgin skewed (| MC| > 0.3)Finansal, log-normal veri

Karar Akışı#

[Veri normal mi?] ↓ ├── Evet, kesin → Z-score │ ├── Yakın → Modified Z (MAD) │ └── Hayır, skewed ↓ ├── Hafif → Tukey's IQR (k=1.5) │ └── Belirgin → Adjusted Boxplot

Production Notu: Mutlaka Robust Başla#

Production AD pipeline'larında default seçim: modified z-score + adjusted boxplot. Klasik z-score'a yalnızca compliance gerektiğinde (örn. mahkeme delili için) ya da downstream test (Grubbs) zorunlu olduğunda dön.
Modül 2.6 hands-on lab'ında NYC Taxi verisinde 5 farklı detektörün PR-AUC karşılaştırmasını yapacağız: z-score, modified z, IQR, adjusted boxplot, Grubbs (bir sonraki ders). Hangisinin en güçlü olduğunu görselleştirerek göstereceğiz.
👉 Bir sonraki ders
Ders 2.3 — Grubbs Test, Dixon Q-Test, Generalized ESD. Z-score ve IQR'ı hipotez testine çeviriyoruz: 'bu gözlem outlier mı, p-değeri nedir?' Klasik istatistik kapısı. Çoklu outlier için Generalized ESD prosedürü.

Sık Sorulan Sorular

Evet. matplotlib `plt.boxplot(whis=1.5)` parametresiyle değiştirilebilir. `whis=3` daha konservatif, `whis=1.0` daha agresif. seaborn da `whis` parametresi sunar. Adjusted boxplot için seaborn'da doğrudan desteği yok — Python'da elle medcouple ekleyerek özel boxplot çizebilirsin.

Yorumlar & Soru-Cevap

(0)
Yorum yazmak için giriş yap.
Yorumlar yükleniyor...

İlgili İçerikler