screenshot 1

PRODUCTION-READY DATA SCIENCE: KİRLİ VERİDEN İLERİ SEVIYE MANİPÜLASYONA MÜHENDİSLİK PRATİKLERİ

Production-Ready Data Science: Kirli Veriden İleri Seviye Manipülasyona Mühendislik Pratikleri

Yapay zeka ve veri bilimi projelerinin başarısı, kağıt üzerinde ne kadar karmaşık model mimarileri seçtiğimizle değil; üretim (production) ortamına taşıdığımız veriyi ne kadar esnek, modüler ve optimize edilmiş yöntemlerle yönettiğimizle ölçülür. Spagetti kod bloklarıyla dolu, bellek yönetimini göz ardı eden yaklaşımlar, gerçek hayat senaryolarında sistemlerin kilitlenmesine veya sürdürülemez pipeline yapılarına yol açar.

Bu teknik yazı serisinde, bir Yapay Zeka Mühendisi olarak sahada bizzat uyguladığım pratikleri, veri temizleme pipeline mimarilerini ve Pandas kütüphanesinin ölçeklenebilir manipülasyon tekniklerini gerçek dünya verileri üzerinden ele alacağız. Serimizin bu ilk bölümünde, spagetti kod mimarisinden sıyrılarak daha esnek ve production kalitesinde Python yapılarını nasıl kuracağımıza odaklanıyoruz.

 
 

A. Temiz ve Esnek Kodun Temeli: AI Mühendisliği İçin Python Araç Kutusu

Veri işleme pipeline’ları (veri hatları) kurarken ya da modellerimizi API katmanlarına (örneğin FastAPI) entegre ederken yazdığımız kodun modüler ve bellek dostu olması gerekir. Ezbere dayalı kod yazımı yerine, arka plandaki mantığı bilmek projenin teknik borcunu (technical debt) minimuma indirir.

 
1. Keşifsel Veri Analizi (EDA) ile Veriyi Tanıma ve Korelasyon Matrisi

Production ortamına geçmeden önce ham verinin karakteristiğini bilmek, kuracağımız Python fonksiyonlarının esnekliğini belirler. Çalışmalarımızda veri seti olarak popüler Pokemon veri setini ele alarak, özellikler (features) arasındaki doğrusal ilişkileri analiz ediyoruz.

 
🐍 Python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Verinin import edilmesi
data = pd.read_csv('pokemon.csv')

# Veri setinin yapısal haritası
data.info()

Veri setindeki değişkenlerin birbiriyle olan ilişkisini sezgisel grafirlerden öte, istatistiksel bir tabana oturtmak için Korelasyon (Correlation) analizinden yararlanıyoruz. İki feature arasındaki korelasyon katsayısının 1 olması tam doğru orantıyı, –1 olması tam ters orantıyı, 0 olması ise aralarında doğrusal bir bağ olmadığını gösterir. Bu ilişkiyi ısı haritası (Heatmap) üzerinden okumak, ileride yapacağımız Feature Selection (Özellik Seçimi) adımları için hayati önem taşır:

 
🐍 Python
# Özellikler arasındaki korelasyon matrisinin çıkarılması ve görselleştirilmesi
f, ax = plt.subplots(figsize=(13, 13))
sns.heatmap(data.corr(), annot=True, linewidths=0.5, fmt='.1f', ax=ax)
plt.show()

Bu matrisi incelediğimizde, örneğin bir karakterin savunma gücü (Defense) ile özel savunma gücü (Sp. Def) arasında 0.5 düzeyinde pozitif bir ilişki olduğunu görürüz. Bu, feature engineering süreçlerinde bize rehberlik eder.

 
2. Modülerlik, Scope (Kapsam) ve Encapsulation Mantığı

Production seviyesinde kod yazarken en sık yapılan hatalardan biri, global değişken havuzunu kirletmektir. Python’da değişkenlerin geçerlilik alanları Local, Global ve Built-in scope olarak üçe ayrılır.

  • Global Scope: Ana gövdede tanımlanan ve her yerden erişilebilen değişkenlerdir.

  • Local Scope: Sadece tanımlandığı fonksiyonun içinde yaşayan değişkenlerdir.

  • Built-in Scope: Python’ın çekirdeğinde halihazırda tanımlanmış olan len, print, type gibi anahtar kelimelerdir. Bu isimlerin değişken adı olarak seçilmemesi sistem sağlığı açısından kritiktir.

 
🐍 Python
# Global ve Local Scope Davranışı
x = 2  # Global

def calculate_power():
    x = 3  # Local
    return x

print(f"Global Değişken X: {x}")                  # Çıktı: 2
print(f"Fonksiyon İçi (Local) Değişken X: {calculate_power()}")  # Çıktı: 3

Eğer local scope içerisinde aranan değişken bulunamazsa, Python otomatik olarak bir üst katmana yani global scope’a yönelir:

 
🐍 Python
x = 5  # Global

def multiply_factor():
    y = 2 * x  # Local scope'ta x yok, globaldeki x=5 kullanılıyor
    return y

print(multiply_factor())  # Çıktı: 10
İleri Seviye Modülerlik: İç İçe Fonksiyonlar (Nested Functions)

Fonksiyon içinde fonksiyon tanımlamak (Encapsulation), sadece o fonksiyon ailesine özgü iş mantıklarını korumak ve dış dünyadan izole etmek için mükemmel bir yöntemdir:

 
🐍 Python
def elite_combat_calculator(stat1, stat2):
    """Gelişmiş savaş puanı hesaplayan iç içe fonksiyon mimarisi."""
    def square(value):
        return value ** 2
    
    # İçerideki fonksiyonları kullanarak nihai skoru hesaplama
    total_score = square(stat1) + square(stat2)
    return total_score

print(elite_combat_calculator(3, 4))  # Çıktı: 25
3. Esnek ve Anonim Fonksiyonlar: Lambda, Map ve Esnek Argümanlar

Yapay zeka pipeline’larında bazen fonksiyonlarımızın kaç argüman alacağını önceden kestiremeyebiliriz. Bu durumlarda esnek argüman yapıları (*args ve kwargs) kodumuza jenerik bir güç katar.

 
🐍 Python
# *args: List tabanlı esnek argüman yönetimi
def dynamic_multiplier(*args):
    result = 1
    for num in args:
        result *= num
    return result

print(dynamic_multiplier(1, 2, 3, 4))  # Çıktı: 24

# **kwargs: Dictionary (Sözlük) tabanlı esnek argüman yönetimi
def print_model_metadata(**kwargs):
    for key, value in kwargs.items():
        print(f"Metrik -> {key}: {value}")

print_model_metadata(Optimizer="Adam", LearningRate=0.001, Loss="MSE")
Vektörel Hızda Anonim Yapılar: Lambda ve Map

Büyük veri dizileri üzerinde döngü çalıştırmak yerine fonksiyonel programlama pratiklerini kullanmak, yürütme süresini (execution time) büyük ölçüde düşürür. Lambda, tek satırlık isimsiz fonksiyonlar yazmamızı sağlarken; Map kütüphanesi bu fonksiyonu tüm bir veri dizisine eş zamanlı (vektörel yaklaşımla) uygular.

 
🐍 Python
# Bir veri listesindeki tüm elemanların karesini vektörel olarak hesaplama
data_list = [1, 2, 3]
squared_data = list(map(lambda x: x ** 2, data_list))
print(squared_data)  # Çıktı: [1, 4, 9]
4. List Comprehension: Tek Satırda Performans ve Feature Engineering

Veri analizinde ve özellik mühendisliğinde (feature engineering) en sık başvurduğumuz optimizasyon araçlarından biri List Comprehension yapısıdır. Klasik for ve if-else döngülerini tek satıra indirgeyerek hem kodun okunabilirliğini artırır hem de arka planda daha optimize çalışır.

Karmaşık bir koşul yapısını tek satırda list comprehension ile inşa edelim:

 
🐍 Python
# Koşullu List Comprehension Örneği
numbers = [5, 10, 15]
processed_numbers = [i ** 2 if i == 10 else (i if i < 7 else i + 5) for i in numbers]
print(processed_numbers)  # Çıktı: [5, 100, 20]
Gerçek Dünya Senaryosu: Threshold Değerine Göre Feature Türetme

Veri setimizdeki karakterlerin hız (Speed) değerlerini inceleyelim. Tüm veri setinin hız ortalamasını bir threshold (eşik değer) olarak kabul edip, bu eşiğin üzerindeki karakterleri “high”, altındakileri ise “low” olarak sınıflandıran yeni bir feature (özellik) türetelim:

 
🐍 Python
# Hız eşik değerinin istatistiksel olarak hesaplanması
threshold = data['Speed'].mean()  # Yaklaşık 68.27
print(f"Sistem Hız Eşiği: {threshold}")

# List Comprehension ile yeni bir feature (Speed_Level) üretilmesi
data['Speed_Level'] = ['high' if i > threshold else 'low' for i in data['Speed']]

# Sonuçların doğrulanması (İlk 5 Satır)
print(data[['Speed', 'Speed_Level']].head())

Bu yaklaşımla, spagetti kod bloklarına ve saatler süren DataFrame döngülerine ihtiyaç duymadan, production ortamına uygun, optimize ve ölçeklenebilir veri ön işleme adımlarımızın ilk temelini atmış olduk.

 
 

B. Modelleme Öncesi İlk Savunma Hattı: Veri Temizleme ve Pipeline Mimarisi

Bir yapay zeka veya veri bilimi projesinde, model mimarisine geçmeden önceki en kritik aşama ham veriyi işlenebilir hale getirmektir. Sektördeki genel kural geçerliliğini her zaman korur: “Garbage In, Garbage Out” (Çöp Girerse Çöp Çıkar). Ham veri setleri çoğunlukla eksik değerler (missing data), tutarsız isimlendirmeler, uyumsuz veri tipleri ve model tahminlerini manipüle edebilecek aykırı değerler (outliers) barındırır.

Bu bölümde, ham veriyi baştan sona analiz edip production süreçlerine hazırlamak için kurduğumuz veri ön işleme (preprocessing) ve temizleme pipeline mimarisini ele alacağız.

1. Veri Teşhisi (Data Diagnosis) ve Yapısal Tutarsızlıklar

Temizleme işlemine başlamadan önce verideki anomalileri teşhis etmek gerekir. Sık karşılaştığımız ve pipeline kodlarının patlamasına yol açan yapısal sorunlar şunlardır:

  • Sütun İsimlerindeki Düzensizlikler: Büyük/küçük harf karmaşası (Name, Type 1, HP) kodun okunabilirliğini azaltır. Mühendislik pratiği olarak tüm sütun isimlerinin standart küçük harfe (lowercase) çevrilmesi önerilir.

  • Boşluk Karakteri Problemi: Sütun isimleri arasında boşluk bulunması (örneğin Type 1), Pandas’ın nesne tabanlı sütun çağırma (data.type_1) özelliğini engeller. Bizi daha hantal olan data['Type 1'] syntax’ına zorlar.

  • Eksik Değişkenler (Missing Values): Bir gözlemin belirli bir özelliğe sahip olmaması durumudur (NaN veya None).

  • Dil ve Karakter Kodlama Sorunları: Veri setlerinde yerel dillerden kalan yabancı karakterlerin bulunması kodlama (encoding) hatalarına yol açar.

Verimizin genel yapısını, boyutunu ve eksik veri durumunu hızlıca teşhis etmek için şu temel fonksiyonları pipeline girişine entegre ederiz:

 
🐍 Python
# Verinin matris boyutunu (Row, Column) öğrenme
print(f"Veri Boyutu: {data.shape}")  # Çıktı: (800, 12)

# Sütun isimlerinin ve veri tiplerinin kontrolü
print(data.columns)
2. Keşifsel Veri Analizi (EDA): Frekans Analizi ve Aykırı Değer (Outlier) Teşhisi

Verideki kategorik değişkenlerin dağılımını anlamak için frekans sayımlarından (value_counts()) yararlanırız. Bu, verideki sınıfsal dengesizliği (class imbalance) görmemizi sağlar:

 
🐍 Python
# Kategorik değişkenin frekans dağılımı (Eksik değerleri drop etmeden)
print(data['Type 1'].value_counts(dropna=False).head())
İstatistiki Outlier Teşhisi: Çeyreklikler (Quartiles) ve IQR Temeli

Aykırı değerler (outliers), veri setindeki genel eğilimin tamamen dışında kalan, hatalı veya uç gözlemlerdir. Bir şirketteki 4 kişinin 1 TL, 1 kişinin ise $1000$ TL maaş alması durumunda aritmetik ortalama (Mean) 200.8 TL çıkar ve bizi yanıltır. Ancak veriyi sıralayıp tam ortadaki değeri aldığımız Medyan (Median) bize 1 TL sonucunu verir. Bu yüzden aykırı değerlerin olduğu veri setlerinde medyan ve çeyreklik analizleri hayati önem taşır.

  • Medyan (Q2 / %50 Çeyreklik): Sıralanmış verinin tam ortasındaki değerdir.

  • Lower Quartile (Q1 / %25 Çeyreklik): Medyan ile en küçük değer arasındaki alt yarının medyanıdır.

  • Upper Quartile (Q3 / %75 Çeyreklik): Medyan ile en büyük değer arasındaki üst yarının medyanıdır.

İstatistiki olarak bir değerin outlier olup olmadığını belirlemek için Interquartile Range (IQR) algoritmasını kullanırız:

IQR = Q_3 – Q_1

Alt ve üst sınır eşikleri şu formüllerle hesaplanır:

Alt Sınır = Q_1 – 1.5 * IQR
{Üst Sınır = Q_3 + 1.5 * IQR

Bu sınırların dışında kalan tüm gözlemler istatistiksel olarak aykırı değer kabul edilir. Pandas’ın describe() metodu bize bu çeyreklik haritasını otomatik olarak çıkarır:

 
🐍 Python
# Sayısal değişkenlerin çeyreklik ve dağılım analizleri
data.describe()
3. Görsel Keşifsel Veri Analizi: Box Plot (Kutu Grafiği) Mimarisi

Matematiksel olarak hesapladığımız bu alt ve üst sınırları, aykırı değerleri somut olarak görebilmek adına Box Plot (Kutu Grafiği) ile görselleştiririz. Box plot, verinin dağılımını, medyanını ve dışarıda kalan uç noktalarını (outliers) tek bir grafikte analiz etmemizi sağlar.

 
🐍 Python
# Atak değerlerinin Legendary durumuna göre Box Plot dağılımı
data.boxplot(column='Attack', by='Legendary', figsize=(8, 8))
plt.show()

Yukarıdaki grafik modelinde kutunun ortasındaki çizgi medyanı, kutunun alt ve üst kenarları sırasıyla Q_1 ve Q_3 değerlerini gösterir. En uçtaki çizgilerin (bıyıkların) dışında kalan çemberler (circles) ise az önce formülle hesapladığımız outlier değerlerdir. Pipeline süreçlerinde bu değerleri baskılamak veya veri setinden uzaklaştırmak model sağlığı için kritiktir.

 
4. Tidy Data Prensipleri ve Pivoting Operasyonları

Makine öğrenmesi modelleri, her satırın bir gözlemi (sample) ve her sütunun bir özelliği (feature) temsil ettiği düzenli matris yapılarıyla (Tidy Data) çalışır. Görselleştirme kütüphanelerine (örneğin Seaborn) veri beslerken veya veriyi yeniden yapılandırırken Melt ve Pivot operasyonlarını kullanırız.

Veriyi Eritmek: melt()

Büyük ve geniş tabloları, belirli değişkenleri sabit tutarak daha uzun ve dikey bir formata getirme işlemine eritme (melting) denir:

 
🐍 Python
# İlk 5 satırı izole ederek bir alt küme oluşturalım
data_new = data.head(5)

# 'Name' sütununu sabit tutarak Attack ve Defense özelliklerini dikey forma getirme
melted_data = pd.melt(frame=data_new, id_vars='Name', value_vars=['Attack', 'Defense'])
print(melted_data)
Veriyi Eski Haline Getirmek: pivot()

Eritilmiş veya dikey formdaki veriyi tekrar geniş matris yapısına (eski haline) döndürmek için pivot() fonksiyonunu çağırırız:

 
🐍 Python
# Dikey veriyi yeniden sütun bazlı matrise dönüştürme
pivoted_data = melted_data.pivot(index='Name', columns='variable', values='value')
print(pivoted_data)
5. Veri Birleştirme (Concatenating) ve Tip Dönüşümleri

Farklı kaynaklardan gelen veya pipeline içerisinde bölünen verileri dikey ya da yatay eksende birleştirmek için pd.concat() fonksiyonunu kullanırız.

 
🐍 Python
# Dikey (Vertical) Birleştirme (Axis=0)
data_top = data.head(5)
data_bottom = data.tail(5)
concatenated_v = pd.concat([data_top, data_bottom], axis=0, ignore_index=True)

# Yatay (Horizontal) Birleştirme (Axis=1)
attack_features = data['Attack'].head(5)
defense_features = data['Defense'].head(5)
concatenated_h = pd.concat([attack_features, defense_features], axis=1)
Bellek ve Model Optimizasyonu İçin Tip Dönüşümü (Type Casting)

Veri tiplerinin doğru ayarlanması RAM optimizasyonu sağlar. Özellikle tekrar eden string sütunları category tipine dönüştürmek, makine öğrenmesi kütüphanelerinin (örn: Scikit-Learn) veriyi daha hızlı işlemesini sağlar.

 
🐍 Python
# Sütun veri tiplerini değiştirme (Type Casting)
data['Type 1'] = data['Type 1'].astype('category')
data['Speed'] = data['Speed'].astype('float')

# Dönüşüm sonrası kontrol
print(data[['Type 1', 'Speed']].dtypes)
6. Eksik Veri Yönetimi ve Assert İfadeleri ile Otomatize Test

Veri setindeki boş değerleri (NaN) handle etmek için önümüzde 4 senaryo bulunur:

  1. Olduğu gibi bırakmak: Eğer eksiklik bir anlam ifade ediyorsa.

  2. Gözlemi silmek (dropna()): Veri kaybı göze alınabiliyorsa.

  3. Sabit değerle doldurmak (fillna()): Boş yerlere “empty” veya belirli bir kategorik etiket yazarak.

  4. İstatistiki imputasyon: Boş değerleri ilgili sütunun Mean veya Median değerleriyle doldurarak.

Pipeline akışının doğruluğundan emin olmak ve hata yönetimini otomatize etmek için assert (doğrulama) ifadelerini kullanırız. assert ifadesi, arkasından gelen şart True ise sessiz kalır; False ise kod akışını keserek AssertionError fırlatır.

 
 
🐍 Python
# Eksik değer barındıran sütunu temizleme pratikleri
data_clean = data.copy()

# Sütundaki NaN değerleri kalıcı olarak datasetten düşürelim
data_clean['Type 2'].dropna(inplace=True)

# PIPELINE TEST ADIMI: Type 2 sütununda gerçekten null değer kaldı mı?
# Eğer null değer kalmadıysa kod sessizce bir sonraki adıma geçecektir.
assert data_clean['Type 2'].notnull().all()

# Veri tipi doğrulama testi
assert data_clean['Speed'].dtype == np.float64

Bu assert kontrol mekanizmaları sayesinde, veri temizleme pipeline’ımızda gözden kaçabilecek herhangi bir anomalinin makine öğrenmesi modeline beslenmesini kesin olarak engellemiş oluyoruz.

Veri ön işleme savunma hattımızı başarıyla kurduk. Serimizin bir sonraki yazısında, veri mühendisliğinin kalbine inerek Pandas mimarisinin derinliklerini ve yerleşik analitik araçlarını inceleyeceğimiz “C. Büyük Veriyi Yönetmek: Pandas Mimarisinin Temelleri ve Bellek Yönetimi” başlığıyla devam edeceğiz.

 

C. Büyük Veriyi Yönetmek: Pandas Mimarisinin Temelleri ve Zaman Serileri (Time Series)

Veri biliminde spagetti kodlardan arınmış, ölçeklenebilir yapılar kurmanın bir sonraki adımı, verinin ana taşıyıcı omurgası olan Pandas mimarisini ve bellek (RAM) üzerindeki çalışma mantığını derinlemesine kavramaktır. Gerçek dünya projelerinde veri her zaman hazır CSV dosyaları olarak gelmez; bazen farklı veri akışlarından (stream) anlık olarak sözlükler (dictionaries) ya da listeler halinde beslenir. Ayrıca sistem logları, borsa hareketleri veya IoT sensör verileri gibi zamana bağlı projelerde Zaman Serileri (Time Series) mimarisini yönetmek, kıdemli bir yapay zeka mühendisinin en temel reflekslerinden biridir.

Bu bölümde; sıfırdan veri çerçeveleri (DataFrame) inşa etmeyi, histogramların istatistiksel derinliklerini ve Pandas’ın zaman serilerine özel indeksleme ve yeniden örnekleme (resampling) yeteneklerini inceleyeceğiz.

1. Sıfırdan DataFrame İnşa Etme ve Broadcasting Pratikleri

Veri hattınızın (pipeline) ara adımlarında elinizdeki ham listeleri birleştirip production kalitesinde DataFrame yapılarına dönüştürmeniz gerekebilir. Bu süreçte jenerik Python listelerini zip mimarisiyle birleştirip sözlükler üzerinden yapısal matrisler oluşturabiliriz.

 
🐍 Python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Sensör veya kaynak bazlı ham veri listeleri
country_list = ["Spain", "France"]
population_list = ["11", "12"]

# Listelerin ve etiketlerin jenerik olarak ziplenmesi ve sözlüğe (dictionary) dönüştürülmesi
list_labels = ["country", "population"]
list_cols = [country_list, population_list]

zipped = list(zip(list_labels, list_cols))
data_dict = dict(zipped)

# DataFrame'in sıfırdan (from scratch) inşa edilmesi
df = pd.DataFrame(data_dict)
print(df)
Geniş Veri Atamaları: Broadcasting Teknikleri

Veri çerçevesine yeni bir özellik (feature) eklerken, her gözleme farklı değerler atayabileceğimiz gibi, tüm sütunu tek bir default değerle de domine edebiliriz. Pandas kütüphanesinde tüm matrise tek bir skalar değeri yayma işlemine Broadcasting denir:

 
🐍 Python
# 1. Senaryo: Sütuna farklı spesifik değerler atama
df['capital'] = ["Madrid", "Paris"]

# 2. Senaryo: Broadcasting ile tüm sütuna tek bir skalar değer basma
df['income'] = 0
print(df)
2. İleri Seviye Görsel EDA: Normalizasyon ve Kümeler Dağılımı (Cumulative Histograms)

Verinin frekans dağılımını gösteren histogram grafikleri, veri bilimi süreçlerinde verinin istatistiksel karakterini anlamak için sıkça kullanılır. Ancak saf frekans değerleri yerine veriyi olasılıksal boyuta taşımak için Normalizasyon ve trend takibi için Kümülatif Dağılım Fonksiyonu (CDF – Cumulative Distribution Function) yaklaşımlarından yararlanırız.

 
🐍 Python
# Tüm sayısal değişkenlerin tek ekranda görselleştirilmesi (Alt grafik mimarisi)
data.plot(subplots=True, figsize=(10, 10))
plt.show()

Gelişmiş histogram parametreleri ile veriyi 0 ile 1 arasında normalize edip (normed=True veya modern Pandas sürümlerinde density=True) olasılık yoğunluğuna çevirebiliriz. Aynı zamanda cumulative=True parametresiyle verinin birikimli frekans artış hızını izleyebiliriz:

 
🐍 Python
# Normalizasyon ve Kümülatif Histogram Analizi
fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8))

# Olasılık Yoğunluğuna Göre Normalize Edilmiş Histogram
data.plot(kind="hist", y="Attack", bins=50, density=True, ax=axes[0], title="Normalize Yoğunluk")

# Kümülatif (Birikimli) Histogram (CDF Temsili)
data.plot(kind="hist", y="Attack", bins=50, density=True, cumulative=True, ax=axes[1], title="Kümülatif Dağılım (CDF)")
plt.show()

Kümülatif grafikler, belirli bir eşik değerinin altındaki gözlemlerin tüm veri setine olan oranını (örneğin “Atak gücü 100’ün altında olan karakterler tüm verinin %80’ini oluşturuyor” gibi) doğrudan okumamızı sağlar.

 
3. Zaman Serileri Mimarisi (Pandas Time Series) ve DateTime İndeksleme

Yapay zeka projelerinde verinin zamana bağlı loglardan (Timestamp) oluşması durumunda, klasik integer indeksleme (0, 1, 2…) yerine DateTimeIndex yapısına geçiş yaparız. Bu mimari, zaman dilimlerine göre hızlı dilimleme (slicing) ve filtreleme yapmamıza olanak tanır.

Elimizdeki string tabanlı tarih verilerini ISO 8601 standardına uygun datetime nesnelerine dönüştürerek veri çerçevemizin ana indeksi haline getirelim:

 
 
 
🐍 Python
# String tabanlı tarih serisi oluşturma
raw_time = ["1992-01-10", "1992-03-15", "1992-03-16", "1993-03-15", "1993-03-16"]

# ISO 8601 standardına uygun DateTime nesnelerine dönüşüm
datetime_index = pd.to_datetime(raw_time, format='%Y-%m-%d')

# Pokemon veri setinin ilk 5 satırına zaman indeksi giydirme
data_time = data.head(5).copy()
data_time.index = datetime_index
print(data_time[['Name', 'Attack']])

Artık verimiz zamana duyarlı bir Time Series veri çerçevesidir. Bu yapı sayesinde string formatında tarih sorguları atarak .loc üzerinden doğrudan zaman dilimi bazlı alt kümeleme (slicing) operasyonları gerçekleştirebiliriz:

 
🐍 Python
# Belirli bir tarihe ait gözlemin çağrılması
print(data_time.loc["1993-03-16"])

# İki zaman aralığındaki verilerin dilimlenmesi (Time-Slice)
print(data_time.loc["1992-03-15":"1993-03-15"])
4. Yeniden Örnekleme (Resampling) ve Interpolasyon Teknikleri

Zaman serisi verilerinde, ham verinin frekansını değiştirmek (örneğin günlük gelen log verilerini aylık ortalamalara veya yıllık maksimum değerlere indirgemek) en sık yaptığımız veri mühendisliği adımlarından biridir. Bu işleme Resampling (Yeniden Örnekleme) denir.

  • M (Month) parametresi veriyi aylık frekansa çeker.

  • A (Year / Annual) parametresi veriyi yıllık frekansa çeker.

 
🐍 Python
# Yıllık bazda yeniden örnekleme (Resampling) yaparak ilgili yılların ortalama değerlerini hesaplama
yearly_average = data_time.resample("A").mean()
print(yearly_average[['Attack', 'Defense']])
Eksik Zaman Dilimlerini Doldurma: Lineer İnterpolasyon (interpolate)

Veriyi aylık bazda örneklediğimizde, ham verimizde ilgili aylara ait gözlem yoksa, Pandas bu satırları NaN (boş değer) olarak üretir. Pipeline akışında bu boş zaman dilimlerini mantıklı istatistiksel trendlerle doldurmak için Lineer İnterpolasyon (Linear Interpolation) yöntemine başvururuz. Lineer interpolasyon, iki bilinen nümerik nokta arasını doğrusal artan/azalan adımlarla doldurur:

 
🐍 Python
# Aylık bazda örnekleme yaptığımızda veri olmayan aylar NaN gelecektir
monthly_resampled = data_time.resample("M").mean()

# PIPELINE TEMİZLEME ADIMI: Boş ayları lineer interpolasyon yöntemiyle doldurma
interpolated_data = monthly_resampled.interpolate("linear")
print(interpolated_data[['Attack', 'Speed']].head(5))

Bu sayede, zaman serisindeki eksik ve kopuk veri noktaları, geçmiş ve gelecek zamandaki gerçek gözlemlerin trend doğrultusuna uygun olarak matematiksel bir tutarlılıkla doldurulmuş olur.

Pandas mimarisinin temellerini, kümülatif olasılık dağılımlarını ve zaman serisi komponentlerini production seviyesinde işlemeyi tamamladık. Serimizin bir sonraki ve final bölümünde, büyük ölçekli feature engineering operasyonlarında hızımızı zirveye çıkaracak gelişmiş filtreleme ve gruplama (split-apply-combine) tekniklerini inceleyeceğimiz “D. Ölçeklenebilir Veri Manipülasyonu: İleri Seviye Pandas Teknikleri” başlığıyla devam edeceğiz.

 
 

D. Ölçeklenebilir Veri Manipülasyonu: Gelişmiş Pandas Teknikleri ve Gruplama (Groupby) Mimarisi

Büyük ölçekli yapay zeka projelerinde veriyi model mimarisine beslemeden önceki son adım, veri çerçevelerini profesyoneller gibi dilimlemek, filtrelemek ve ham veriden yeni özellikler türetmektir (Feature Engineering). Spagetti döngülerle (for index, row in df.iterrows()) DataFrame üzerinde dönmek, büyük veri setlerinde RAM kilitlenmelerine ve aşırı zaman kaybına yol açar. Bir Yapay Zeka Mühendisi olarak bu süreçleri hızlandırmak amacıyla Pandas’ın vektörel operasyonlarını, hiyerarşik indekslemeyi ve Split-Apply-Combine (Böl-Uygula-Birleştir) mimarisini kullanırız.

Serimizin bu final bölümünde, veri manipülasyonunun en güçlü production tekniklerini ve optimizasyon yöntemlerini ele alacağız.

 
1. Gelişmiş İndeksleme, Dilimleme (Slicing) ve Seçim Stratejileri

Pandas üzerinde veri seçerken integer indeksler ile etiket (label) tabanlı indeksler arasındaki ayrımı netleştirmek gerekir. Pipeline süreçlerinde hata payını sıfıra indirmek ve veri bozulmalarını engellemek için doğrudan .loc (Label location) mekanizmasını kullanırız.

Veri setimizdeki default tam sayı indeksini, karakterlerin veri setindeki numaralarını temsil eden # (Number) sütunu ile güncelleyerek başlayalım:

 
🐍 Python
# Sütunu kalıcı olarak ana indeks haline getirme (1'den başlayan yeni indeks mimarisi)
data.set_index('#', inplace=True)

# Tek bir hücreye erişim (1. indeksli satırın HP sütunu)
print(data.loc[1, 'HP'])  # Çıktı: 45

# Belirli sütunları jenerik bir liste halinde seçme
selected_features = data[['HP', 'Attack']]
İleri Seviye Dilimleme (Slicing) Operasyonları

Kapsamlı bir matris dilimlemesi yaparken hem satır aralıklarını hem de sütun aralıklarını aynı anda yönetebiliriz. Pandas bize string etiketler üzerinden de sıralı dilimleme yapma imkanı tanır:

 
🐍 Python
# 1'den 10'a kadar olan satırları, 'HP' sütunundan 'Defense' sütununa kadar dilimleme
matrix_slice = data.loc[1:10, 'HP':'Defense']

# Belirli bir sütundan başlayıp matrisin sonuna kadar gitme (From Speed to End)
speed_to_end_slice = data.loc[1:10, 'Speed':]
2. Çoklu Koşul Filtreleme ve Hücre Bazlı Seçimler

Matris filtrelemede mantıksal operatörler yardımıyla Boolean maskeler oluştururuz. Hız ve RAM optimizasyonu için filtrelenmiş matrisin tamamını çağırmak yerine, sadece ilgilendiğimiz hedef hedef sütunu (Target feature) izole edebiliriz.

 
🐍 Python
# Gelişmiş Filtreleme: Hızı 15'ten küçük olan gözlemlerin sadece 'HP' değerlerini izole etme
speed_filter = data['Speed'] < 15
filtered_hp = data.loc[speed_filter, 'HP']
print(filtered_hp)
3. Vektörel Veri Dönüştürme (Transforming Data) ve Lambda Mimarisi

DataFrame üzerinde satır satır döngü çalıştırmak yerine, Pandas’ın .apply() metodunu kullanarak fonksiyonları tüm seriye vektörel olarak uygularız. Bu yöntem arka planda optimize edilmiş C kodu gibi çalışarak işlem sürelerini dramatik şekilde düşürür.

 
🐍 Python
# Klasik Python Fonksiyonu ile Dönüşüm (Type-1)
def half_division(number):
    return number / 2

data['HP_Half'] = data['HP'].apply(half_division)

# Üretim Kalitesinde Lambda ile Tek Satırda Dönüşüm (Type-2)
data['HP_Lambda_Half'] = data['HP'].apply(lambda x: x / 2)
Ham Veriden Yeni Feature Türetme (Feature Engineering)

Mevcut sütunları birbiriyle matematiksel kombinasyonlara sokarak modelin öğrenme kapasitesini artıracak jenerik özellikler (Örn: Total_Power) türetebiliriz:

 
🐍 Python
# Atak ve Savunma güçlerinin birleşiminden jenerik bir güç feature'ı türetme
data['Total_Power'] = data['Attack'] + data['Defense']
4. Hiyerarşik İndeksleme (Multi-Index) Yapıları

Veriyi birden fazla boyuta göre gruplayıp analiz etmek istediğimizde hiyerarşik indeks (MultiIndex) mimarisini kurarız. Bu sayede verinin iç içe geçmiş alt kırılımlarını istatistiksel olarak izlemek kolaylaşır.

 
🐍 Python
# İki kategorik sütunu hiyerarşik index (Multi-index) mimarisine geçirme
hierarchical_data = data.set_index(['Type 1', 'Type 2'])

Bu hiyerarşik yapıda, dış indeks (Type 1) en dış katmanı korurken, iç indeks (Type 2) alt sınıfları listeler. Bu sayede örneğin “Su” veya “Çim” karakterlerinin alt kırılımlarındaki yapısal boşlukları net bir şekilde analiz edebiliriz.

 
5. Pivot Tablolar ve Matris Şekillendirme (Stacking & Unstacking)

Gelişmiş analitik raporlamalarda ve feature türetme süreçlerinde verinin eksenlerini değiştirmek için pivot operasyonlarından yararlanırız. Bu senaryoyu canlandırmak adına anlık bir klinik tedavi veri seti oluşturalım:

 
🐍 Python
# Klinik Deney Veri Setinin Oluşturulması
clinical_dict = {
    "treatment": ["A", "A", "B", "B"],
    "gender": ["Female", "Male", "Female", "Male"],
    "response": [10, 45, 5, 72],
    "age": [15, 4, 65, 9]
}
df_clinical = pd.DataFrame(clinical_dict)

# Pivoting: Satır değerlerini sütun başlıklarına taşıma
# İndeks: Tedavi Türü, Sütunlar: Cinsiyet, Değerler: Tedaviye Yanıt Puanı
pivoted_df = df_clinical.pivot(index='treatment', columns='gender', values='response')
print(pivoted_df)
Matris Boyut Değişimleri: Stack ve Unstack

Çoklu indekse sahip yapılarda sütunları satır indeksine eritmeye stack(), satır indeksindeki hiyerarşik kırılımları tekrar sütun formuna getirmeye ise unstack() denir. İndeks seviyelerinin yerini değiştirmek için ise swaplevel() fonksiyonu kullanılır.

 
🐍 Python
# Hiyerarşik kırılımların yerini değiştirme (Dış indeks ile iç indeksi takas etme)
df_swapped = df_clinical.set_index(['treatment', 'gender']).swaplevel(0, 1)
6. Veri Ambarının Kalbi: Split-Apply-Combine ve Groupby Operasyonları

Makine öğrenmesi ve veri mühendisliği pipeline’larında veriyi segmentlere ayırıp (Split), her segmente bir matematiksel işlem uygulayıp (Apply) ve sonuçları nihai bir özet tablo olarak birleştirme (Combine) sürecine Groupby mimarisi denir.

 
🐍 Python
# 1. Senaryo: Tedavi türüne göre gruplayıp tüm sayısal sütunların ortalamasını (Mean) hesaplama
print(df_clinical.groupby('treatment').mean())

# 2. Senaryo: Sadece belirli bir hedef sütunu (Age) izole edip alt grupların maksimum değerini bulma
print(df_clinical.groupby('treatment')['age'].max())

# 3. Senaryo: Çoklu metrik analizi (Aynı anda hem minimum hem maksimum değerleri hesaplama)
print(df_clinical.groupby('treatment')[['age', 'response']].agg([np.min, np.max]))

Bu groupby ve aggregation adımları, devasa ham veri havuzlarından model girdisi olabilecek mikro istatistikler ve sıkıştırılmış analitik özetler türetmemizi sağlayarak pipeline mimarimizin optimizasyon aşamasını tamamlar.

 

Serinin Sonu: Production-Ready Veri Pipeline'larının Gücü

Bu 4 bölümlük teknik yazı serisinde, ham ve kirli bir veri setinin Yapay Zeka ve Veri Bilimi Mühendisliği refleksleriyle adım adım nasıl işlenebilir, modüler ve production-ready (üretime hazır) bir veri hattına (pipeline) dönüştürüleceğini ele aldık.

Özetlemek gerekirse; spagetti kod bloklarından sıyrılarak esnek Python fonksiyonları ve lambda mimarilerini kurguladık. Ardından, model mimarilerinin en büyük düşmanı olan kirli verileri, anomali tespiti ve assert tabanlı otomatize test mekanizmalarıyla temizledik. Pandas’ın zaman serileri üzerindeki resampling ve interpolasyon yetenekleriyle zaman boyutuna hükmederek, son aşamada vektörel veri manipülasyonu ve split-apply-combine (böl-uygula-birleştir) pratikleriyle feature engineering süreçlerimizi optimize ettik.

Burada paylaştığımız tüm mühendislik pratikleri, modellerinizin sadece yerel bilgisayarınızda değil, gerçek dünya sistemlerinde ve canlı API katmanlarında da ölçeklenebilir ve sürdürülebilir çalışmasını sağlayacak bir temel niteliğindedir.

 

Kaynak Kodlar ve GitHub Deposu

Bu seride ele aldığımız tüm veri temizleme, zaman serisi analizi, ileri seviye Pandas manipülasyonları ve feature engineering adımlarına ait çalışan canlı kod bloklarına, Jupyter Notebook içeriğine ve kullanılan veri setlerine doğrudan aşağıdaki GitHub deposu üzerinden erişebilirsiniz:

 GitHub Repository: Rasittekin18 / Data_Science

Depoyu yıldızlamayı (star) ve production süreçlerinde karşılaştığınız tıkanıklıklar için issue açarak katkı sağlamayı unutmayın!

 
 
 

Yorum bırakın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir