Veri İşleme: pandas ve NumPy Temelleri
Excel'de hiç büyük bir veri setiyle çalıştın mı? Binlerce satırı filtreleme, toplam alma, grafiğe dökme... Bir noktadan sonra Excel donuyor, formüller karmaşıklaşıyor ve "bunu programla yapsam keşke" diyorsun. İşte pandas tam olarak bu ihtiyacı karşılıyor — Excel'in yapabildiği her şeyi ve çok daha fazlasını, Python kodu ile yapmanı sağlıyor.
Bu derste önce pandas'ın temelini oluşturan NumPy'ı tanıyacak, ardından pandas ile veri okuma, filtreleme, gruplama, temizleme ve birleştirme işlemlerini öğreneceksin. Ders sonunda gerçek bir satış verisi analizi projesi yapacağız.
1. Neden pandas?
📊 Analoji: Excel'in Programlanabilir Hali
Excel'i düşün: satırlar, sütunlar, hücreler. Filtre koyarsın, TOPLA formülü yazarsın, pivot tablo oluşturursun. pandas tam olarak bu — ama Excel yerine Python kodu ile kontrol ediyorsun. Bir formül yerine bir satır kod, bir makro yerine bir fonksiyon.
Fark ne? Excel 1 milyon satırda tıkanır. pandas milyonlarca satırı saniyeler içinde işler. Excel'de tekrarlayan işler için makro yazmak zahmetlidir. pandas'ta bir script yazarsın, her seferinde aynı analizi otomatik çalıştırırsın.
pandas Python'un veri bilimi ekosisteminin merkezinde durur. Veri okuma, temizleme, dönüştürme, analiz ve görselleştirme — hepsinin başlangıç noktası pandas'tır.
2. NumPy: pandas'ın Temeli
pandas'ı anlamadan önce NumPy'ı bilmek gerekir. pandas, verileri arka planda NumPy dizileri (ndarray) olarak tutar. NumPy'ın hız avantajı pandas'a da yansır.
ndarray Nedir?
Python'un yerleşik list'i her türden veri tutar — string, int, float karışık olabilir. Bu esneklik bir bedel getirir: yavaşlık. NumPy'ın ndarray'i ise tek tip veri tutar (hepsi int, hepsi float). Bu sayede bellekte ardışık depolanır ve C seviyesinde hızlı işlem yapılır.
import numpy as np
# Python listesi
python_list = [1, 2, 3, 4, 5]
# NumPy dizisi
numpy_array = np.array([1, 2, 3, 4, 5])
print(type(numpy_array)) # <class 'numpy.ndarray'>
print(numpy_array.dtype) # int64
print(numpy_array.shape) # (5,)Temel Operasyonlar
NumPy'ın en güçlü özelliği vektörel operasyonlar. Döngü yazmadan tüm elemanlara işlem uygularsın:
import numpy as np
fiyatlar = np.array([100, 200, 350, 450, 600])
# Tüm fiyatlara %18 KDV ekle — döngü yok!
kdv_dahil = fiyatlar * 1.18
print(kdv_dahil) # [118. 236. 413. 531. 708.]
# Karşılaştırma — boolean dizi döner
pahalı = fiyatlar > 300
print(pahalı) # [False False True True True]
# Boolean indexing — filtreleme
print(fiyatlar[pahalı]) # [350 450 600]
# İstatistik
print(f"Ortalama: {fiyatlar.mean()}") # 340.0
print(f"Toplam: {fiyatlar.sum()}") # 1700
print(f"Max: {fiyatlar.max()}") # 600For döngüsüyle aynı işi yapmaya kıyasla bu yaklaşım hem daha okunabilir hem çok daha hızlı.
Broadcasting
Farklı boyuttaki diziler arasında işlem yapabilirsin. NumPy küçük diziyi otomatik "genişletir":
import numpy as np
# 3x3 matris
matris = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Her sütuna farklı çarpan uygula
carpanlar = np.array([10, 100, 1000])
sonuc = matris * carpanlar
print(sonuc)
# [[ 10 200 3000]
# [ 40 500 6000]
# [ 70 800 9000]]carpanlar dizisi (3 eleman) her satıra otomatik olarak uygulandı. Elle döngü yazmaya gerek kalmadı.
Performans Farkı: list vs ndarray
NumPy'ın gerçek gücünü rakamlarla görelim:
import numpy as np
import time
boyut = 1_000_000
# Python listesi ile
python_list = list(range(boyut))
start = time.time()
result_list = [x * 2 for x in python_list]
list_sure = time.time() - start
# NumPy dizisi ile
numpy_array = np.arange(boyut)
start = time.time()
result_numpy = numpy_array * 2
numpy_sure = time.time() - start
print(f"List: {list_sure:.4f} saniye") # ~0.08 saniye
print(f"NumPy: {numpy_sure:.4f} saniye") # ~0.001 saniye
print(f"NumPy {list_sure / numpy_sure:.0f}x daha hızlı!") # ~50-100xBu fark büyük veri setlerinde kritik hale gelir. Milyonlarca satırlık bir CSV dosyasını işlerken saniyelerle dakikalar arasında seçim yapmak gibi.
💡 İpucu: NumPy'ı "hızlı matematik motoru" olarak düşün. pandas ise bu motorun üzerine kurulmuş kullanıcı dostu bir arayüz. Doğrudan NumPy kullanman gereken durumlar (makine öğrenimi, bilimsel hesaplama) dışında pandas ile çalışmak çoğu zaman yeterli.
3. pandas Kurulum ve Temel Yapılar
Kurulum
pip install pandas numpypandas kurulunca NumPy da otomatik gelir (bağımlılık). Excel dosyaları okumak istersen ek olarak openpyxl paketini de kurabilirsin:
pip install openpyxl # .xlsx dosyaları içinSeries: Tek Boyutlu Veri
Series, etiketli bir NumPy dizisidir. Bir sütun gibi düşünebilirsin — hem veriler hem de her verinin bir etiketi (index) var:
import pandas as pd
# Listeden Series oluşturma
notlar = pd.Series([85, 92, 78, 95, 88],
index=["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"])
print(notlar)
# Ali 85
# Ayşe 92
# Mehmet 78
# Zeynep 95
# Can 88
# dtype: int64
# İndeksle erişim
print(notlar["Ayşe"]) # 92
print(notlar[notlar > 90]) # Ayşe: 92, Zeynep: 95
# Temel istatistikler
print(f"Ortalama: {notlar.mean()}") # 87.6
print(f"Medyan: {notlar.median()}") # 88.0DataFrame: İki Boyutlu Veri — Asıl Yıldız
DataFrame, pandas'ın kalbidir. Bir Excel tablosu gibi satırlar ve sütunlardan oluşur. Her sütun bir Series'tir:
import pandas as pd
# Dict'ten DataFrame oluşturma
veri = {
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"departman": ["IT", "HR", "IT", "Finans", "HR"],
"maas": [15000, 18000, 22000, 20000, 16000]
}
df = pd.DataFrame(veri)
print(df)
# isim yas departman maas
# 0 Ali 25 IT 15000
# 1 Ayşe 30 HR 18000
# 2 Mehmet 35 IT 22000
# 3 Zeynep 28 Finans 20000
# 4 Can 32 HR 16000
# Temel bilgiler
print(f"Boyut: {df.shape}") # (5, 4) — 5 satır, 4 sütun
print(f"Sütunlar: {list(df.columns)}")
print(f"Veri tipleri:\n{df.dtypes}")DataFrame oluşturmanın birkaç farklı yolu vardır:
import pandas as pd
# Liste of dict'lerden
kayitlar = [
{"isim": "Ali", "puan": 85},
{"isim": "Ayşe", "puan": 92},
{"isim": "Mehmet", "puan": 78}
]
df_from_dicts = pd.DataFrame(kayitlar)
# İç içe listelerden
satırlar = [["Ali", 85], ["Ayşe", 92], ["Mehmet", 78]]
df_from_lists = pd.DataFrame(satırlar, columns=["isim", "puan"])
print(df_from_dicts)
print(df_from_lists)
# İkisi de aynı sonucu verirHızlı Keşif Komutları
Bir DataFrame'le ilk tanışma anında kullanacağın komutlar:
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"maas": [15000, 18000, 22000, 20000, 16000]
})
# İlk / son satırlar
print(df.head(3)) # İlk 3 satır
print(df.tail(2)) # Son 2 satır
# Genel bilgi
df.info()
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 3 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 isim 5 non-null object
# 1 yas 5 non-null int64
# 2 maas 5 non-null int64
# Sayısal sütunların istatistikleri
print(df.describe())
# yas maas
# count 5.000000 5.000000
# mean 30.000000 18200.000000
# std 3.807887 2863.564213
# min 25.000000 15000.000000
# ...info() veri tiplerini ve eksik değerleri gösterir. describe() sayısal sütunların temel istatistiklerini verir. Yeni bir veri setiyle çalışırken ilk adımın her zaman bu iki komut olmalı.
4. Dosya Okuma ve Yazma
Gerçek dünyada veriler genellikle dosyalarda yaşar — CSV, JSON, Excel. pandas bunları okumak ve yazmak için güçlü fonksiyonlar sunar.
CSV Okuma ve Yazma
CSV (Comma-Separated Values) veri dünyasının evrensel dili. pandas'ın read_csv() fonksiyonu inanılmaz esnek:
import pandas as pd
# Basit CSV okuma
df = pd.read_csv("satislar.csv")
# Özelleştirilmiş okuma
df = pd.read_csv(
"satislar.csv",
sep=";", # Ayırıcı karakter (Türk Excel'i ; kullanır)
encoding="utf-8", # Karakter kodlaması
parse_dates=["tarih"],# Tarih sütununu datetime'a çevir
index_col="id", # id sütununu indeks yap
usecols=["id", "urun", "fiyat", "tarih"], # Sadece bu sütunları oku
nrows=1000 # İlk 1000 satırı oku (büyük dosyalar için)
)
print(df.head())CSV yazmak da bir o kadar kolay:
import pandas as pd
df = pd.DataFrame({
"urun": ["Laptop", "Mouse", "Klavye"],
"fiyat": [25000, 500, 1200],
"stok": [10, 150, 75]
})
# CSV'ye yaz
df.to_csv("urunler.csv", index=False) # index=False: satır numarası yazma
# Türkçe Excel uyumlu (noktalı virgül + UTF-8 BOM)
df.to_csv("urunler_excel.csv", sep=";", encoding="utf-8-sig", index=False)⚠️ Dikkat: Türkçe karakterler içeren CSV dosyalarını Excel'de açarken
utf-8-sigencoding kullan. Normalutf-8ile Türkçe karakterler bozuk görünebilir.utf-8-sigbaşa BOM (Byte Order Mark) ekler ve Excel bunu doğru yorumlar.
JSON Okuma ve Yazma
API'lardan gelen veriler genellikle JSON formatındadır:
import pandas as pd
# JSON dosyasından okuma
df = pd.read_json("veriler.json")
# API'dan gelen JSON string'den
import json
json_str = '''
[
{"isim": "Ali", "sehir": "İstanbul", "puan": 85},
{"isim": "Ayşe", "sehir": "Ankara", "puan": 92},
{"isim": "Mehmet", "sehir": "İzmir", "puan": 78}
]
'''
df = pd.read_json(json_str)
print(df)
# JSON'a yazma
df.to_json("cikti.json", orient="records", force_ascii=False, indent=2)force_ascii=False parametresi Türkçe karakterlerin korunmasını sağlar. Aksi halde "İstanbul" gibi kelimeler \u0130stanbul şeklinde yazılır.
Excel Okuma ve Yazma
Excel dosyaları ile çalışmak da mümkün (openpyxl paketi gerekir):
import pandas as pd
# Excel'den okuma
df = pd.read_excel("rapor.xlsx", sheet_name="Satışlar")
# Birden fazla sayfa okuma
tum_sayfalar = pd.read_excel("rapor.xlsx", sheet_name=None) # dict döner
print(tum_sayfalar.keys()) # dict_keys(['Satışlar', 'Müşteriler', ...])
# Excel'e yazma
df.to_excel("cikti.xlsx", sheet_name="Sonuçlar", index=False)5. Filtreleme ve Seçim
Veriyi okudun, şimdi içinden istediğin parçaları seçme zamanı. pandas'ta filtreleme dört temel yolla yapılır.
Sütun Seçimi
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"departman": ["IT", "HR", "IT", "Finans", "HR"],
"maas": [15000, 18000, 22000, 20000, 16000]
})
# Tek sütun — Series döner
isimler = df["isim"]
# Birden fazla sütun — DataFrame döner
secim = df[["isim", "maas"]]
print(secim)
# isim maas
# 0 Ali 15000
# 1 Ayşe 18000
# ...Boolean Indexing — En Sık Kullanılan Yöntem
Bir koşul yaz, koşulu sağlayan satırları al:
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"departman": ["IT", "HR", "IT", "Finans", "HR"],
"maas": [15000, 18000, 22000, 20000, 16000]
})
# Maaşı 17000'den yüksek olanlar
yuksek_maas = df[df["maas"] > 17000]
print(yuksek_maas)
# isim yas departman maas
# 1 Ayşe 30 HR 18000
# 2 Mehmet 35 IT 22000
# 3 Zeynep 28 Finans 20000
# Birden fazla koşul: & (ve), | (veya)
it_ve_yuksek = df[(df["departman"] == "IT") & (df["maas"] > 16000)]
print(it_ve_yuksek)
# isim yas departman maas
# 2 Mehmet 35 IT 22000Birden fazla koşulu birleştirirken her koşulu parantez içine almayı unutma. df[df["departman"] == "IT" & df["maas"] > 16000] yazmak hata verir çünkü & operatörü == ve >'den önce değerlendirilir.
.loc[] ve .iloc[]
loc etiket tabanlı, iloc pozisyon tabanlı seçim yapar:
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"maas": [15000, 18000, 22000, 20000, 16000]
})
# iloc — pozisyon ile (0-based)
print(df.iloc[0]) # İlk satır (Series)
print(df.iloc[1:3]) # 2. ve 3. satırlar
print(df.iloc[0, 2]) # 1. satır, 3. sütun → 15000
print(df.iloc[:, 0:2]) # Tüm satırlar, ilk 2 sütun
# loc — etiket ile
df.index = ["a", "b", "c", "d", "e"] # Özel index
print(df.loc["b"]) # "b" etiketli satır
print(df.loc["a":"c"]) # "a"dan "c"ye (c dahil!)
print(df.loc["b", "maas"]) # 18000iloc'ta 1:3 → indeks 1 ve 2 (3 hariç, Python geleneği). loc'ta "a":"c" → a, b ve c (c dahil!). Bu farka dikkat et.
.query() — SQL Benzeri Filtreleme
Karmaşık filtrelerde daha okunabilir bir alternatif:
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can"],
"yas": [25, 30, 35, 28, 32],
"departman": ["IT", "HR", "IT", "Finans", "HR"],
"maas": [15000, 18000, 22000, 20000, 16000]
})
# Boolean indexing ile
sonuc1 = df[(df["departman"] == "IT") & (df["yas"] > 25)]
# query() ile — aynı sonuç, daha okunabilir
sonuc2 = df.query("departman == 'IT' and yas > 25")
print(sonuc2)
# isim yas departman maas
# 2 Mehmet 35 IT 22000
# Değişken kullanımı: @ ile
min_maas = 17000
sonuc3 = df.query("maas > @min_maas")
print(sonuc3)query() özellikle birden fazla koşul kombinasyonu olduğunda kodu çok daha temiz yapar.
6. Gruplama ve Aggregation
SQL'deki GROUP BY ne ise pandas'ta groupby() odur. Veriyi bir sütuna göre grupla, her gruba bir işlem uygula.
groupby() Temelleri
import pandas as pd
df = pd.DataFrame({
"departman": ["IT", "HR", "IT", "Finans", "HR", "IT"],
"calisan": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can", "Deniz"],
"maas": [15000, 18000, 22000, 20000, 16000, 19000]
})
# Departmana göre ortalama maaş
ort_maas = df.groupby("departman")["maas"].mean()
print(ort_maas)
# departman
# Finans 20000.000000
# HR 17000.000000
# IT 18666.666667
# Name: maas, dtype: float64
# Birden fazla aggregation
ozet = df.groupby("departman")["maas"].agg(["mean", "min", "max", "count"])
print(ozet)
# mean min max count
# departman
# Finans 20000.0 20000 20000 1
# HR 17000.0 16000 18000 2
# IT 18666.7 15000 22000 3agg() ile Özelleştirilmiş Aggregation
Farklı sütunlara farklı fonksiyonlar uygulamak istediğinde agg() kullanırsın:
import pandas as pd
df = pd.DataFrame({
"departman": ["IT", "HR", "IT", "Finans", "HR", "IT"],
"calisan": ["Ali", "Ayşe", "Mehmet", "Zeynep", "Can", "Deniz"],
"maas": [15000, 18000, 22000, 20000, 16000, 19000],
"deneyim_yil": [2, 5, 8, 6, 3, 4]
})
sonuc = df.groupby("departman").agg(
ortalama_maas=("maas", "mean"),
max_maas=("maas", "max"),
calisan_sayisi=("calisan", "count"),
toplam_deneyim=("deneyim_yil", "sum")
)
print(sonuc)
# ortalama_maas max_maas calisan_sayisi toplam_deneyim
# departman
# Finans 20000.0 20000 1 6
# HR 17000.0 18000 2 8
# IT 18666.7 22000 3 14pivot_table() — Excel Pivot Tablosu
Excel'deki pivot tablosunun birebir karşılığı:
import pandas as pd
df = pd.DataFrame({
"ay": ["Ocak", "Ocak", "Şubat", "Şubat", "Ocak", "Şubat"],
"departman": ["IT", "HR", "IT", "HR", "IT", "HR"],
"satis": [50000, 30000, 55000, 35000, 48000, 32000]
})
pivot = pd.pivot_table(
df,
values="satis",
index="departman",
columns="ay",
aggfunc="sum"
)
print(pivot)
# ay Ocak Şubat
# departman
# HR 30000 67000
# IT 98000 55000pivot_table() satır-sütun çaprazında özetleme yapar. Raporlama ve veri analizi için vazgeçilmez bir araç.
7. Eksik Veri Yönetimi
Gerçek dünyada veri asla temiz gelmez. Eksik değerler (NaN — Not a Number) her veri setinde karşına çıkacak. pandas eksik veriyle başa çıkmak için güçlü araçlar sunar.
Eksik Veriyi Tespit Etme
import pandas as pd
import numpy as np
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep", None],
"yas": [25, np.nan, 35, 28, 32],
"maas": [15000, 18000, np.nan, np.nan, 16000]
})
print(df)
# isim yas maas
# 0 Ali 25.0 15000.0
# 1 Ayşe NaN 18000.0
# 2 Mehmet 35.0 NaN
# 3 Zeynep 28.0 NaN
# 4 None 32.0 16000.0
# Eksik mi? Boolean matrisi
print(df.isna())
# isim yas maas
# 0 False False False
# 1 False True False
# 2 False False True
# 3 False False True
# 4 True False False
# Sütun başına eksik sayısı
print(df.isna().sum())
# isim 1
# yas 1
# maas 2
# dtype: int64
# Toplam eksik oranı
toplam_hucre = df.shape[0] * df.shape[1]
eksik_oran = df.isna().sum().sum() / toplam_hucre * 100
print(f"Eksik veri oranı: %{eksik_oran:.1f}") # %26.7Eksik Veriyi Silme: dropna()
import pandas as pd
import numpy as np
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep"],
"yas": [25, np.nan, 35, 28],
"maas": [15000, 18000, np.nan, 20000]
})
# Herhangi bir NaN olan satırı sil
temiz = df.dropna()
print(temiz)
# isim yas maas
# 0 Ali 25.0 15000.0
# 3 Zeynep 28.0 20000.0
# Sadece belirli sütunlardaki NaN'lara bak
temiz2 = df.dropna(subset=["maas"])
print(temiz2)
# isim yas maas
# 0 Ali 25.0 15000.0
# 1 Ayşe NaN 18000.0
# 3 Zeynep 28.0 20000.0
# Tüm değerleri NaN olan satırları sil (how="all")
df2 = pd.DataFrame({
"a": [1, np.nan, 3],
"b": [np.nan, np.nan, 6]
})
print(df2.dropna(how="all")) # Sadece tamamı NaN olan satır silinirEksik Veriyi Doldurma: fillna()
Silmek yerine doldurmak genellikle daha iyi bir strateji:
import pandas as pd
import numpy as np
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep"],
"yas": [25, np.nan, 35, 28],
"maas": [15000, np.nan, np.nan, 20000]
})
# Sabit değerle doldur
df_sabit = df.fillna({"yas": 0, "maas": df["maas"].mean()})
print(df_sabit)
# isim yas maas
# 0 Ali 25.0 15000.0
# 1 Ayşe 0.0 17500.0
# 2 Mehmet 35.0 17500.0
# 3 Zeynep 28.0 20000.0
# Önceki değerle doldur (forward fill)
df_ffill = df["maas"].ffill()
print(df_ffill)
# 0 15000.0
# 1 15000.0 ← Önceki değeri aldı
# 2 15000.0 ← Önceki değeri aldı
# 3 20000.0
# Sonraki değerle doldur (backward fill)
df_bfill = df["maas"].bfill()
print(df_bfill)
# 0 15000.0
# 1 20000.0 ← Sonraki değeri aldı
# 2 20000.0 ← Sonraki değeri aldı
# 3 20000.0Hangi stratejiyi seçeceğin verinin doğasına bağlı. Yaş için ortalama ile doldurmak mantıklı olabilir. İsim için ise "Bilinmiyor" string'i daha uygun. Finansal veriler için forward fill (son bilinen değeri taşıma) yaygın bir tercihtir.
8. DataFrame Birleştirme
Gerçek projelerde veri genellikle tek bir tabloda olmaz. Müşteriler bir tabloda, siparişler başka tabloda, ürünler başka tabloda. Bunları birleştirmen gerekir.
merge() — SQL JOIN Karşılığı
import pandas as pd
musteriler = pd.DataFrame({
"musteri_id": [1, 2, 3, 4],
"isim": ["Ali", "Ayşe", "Mehmet", "Zeynep"]
})
siparisler = pd.DataFrame({
"siparis_id": [101, 102, 103, 104, 105],
"musteri_id": [1, 2, 1, 3, 5], # 5 numaralı müşteri yok!
"tutar": [500, 1200, 300, 800, 950]
})
# INNER JOIN — sadece eşleşenler
inner = pd.merge(musteriler, siparisler, on="musteri_id", how="inner")
print(inner)
# musteri_id isim siparis_id tutar
# 0 1 Ali 101 500
# 1 1 Ali 103 300
# 2 2 Ayşe 102 1200
# 3 3 Mehmet 104 800
# musteri_id=4 (Zeynep) ve musteri_id=5 eşleşmediği için yok
# LEFT JOIN — sol tablodaki herkes
left = pd.merge(musteriler, siparisler, on="musteri_id", how="left")
print(left)
# musteri_id isim siparis_id tutar
# 0 1 Ali 101.0 500.0
# 1 1 Ali 103.0 300.0
# 2 2 Ayşe 102.0 1200.0
# 3 3 Mehmet 104.0 800.0
# 4 4 Zeynep NaN NaN ← Siparişi yok, NaN
# Sütun adları farklıysa
df_a = pd.DataFrame({"id_col": [1, 2], "deger": ["x", "y"]})
df_b = pd.DataFrame({"ref_col": [1, 2], "bilgi": ["a", "b"]})
birlesik = pd.merge(df_a, df_b, left_on="id_col", right_on="ref_col")
print(birlesik)concat() — Alt Alta veya Yan Yana Birleştirme
import pandas as pd
# Alt alta birleştirme (satır ekleme)
ocak = pd.DataFrame({
"urun": ["Laptop", "Mouse"],
"satis": [10, 50]
})
subat = pd.DataFrame({
"urun": ["Laptop", "Klavye"],
"satis": [12, 30]
})
birlesik = pd.concat([ocak, subat], ignore_index=True)
print(birlesik)
# urun satis
# 0 Laptop 10
# 1 Mouse 50
# 2 Laptop 12
# 3 Klavye 30
# Yan yana birleştirme (sütun ekleme)
isimler = pd.DataFrame({"isim": ["Ali", "Ayşe"]})
puanlar = pd.DataFrame({"puan": [85, 92]})
yan_yana = pd.concat([isimler, puanlar], axis=1)
print(yan_yana)
# isim puan
# 0 Ali 85
# 1 Ayşe 92ignore_index=True parametresi yeni bir 0'dan başlayan index oluşturur. Yoksa orijinal index'ler korunur ve tekrar edebilir (0, 1, 0, 1 gibi).
💡 İpucu:
merge()SQL benzeri birleştirme (anahtar sütunla),concat()ise fiziksel yapıştırma (alt alta veya yan yana). İkisi farklı işler yapar — doğru olanı seç.
9. Gerçek Dünya Projesi: Satış Verisi Analizi
Şimdi öğrendiğimiz her şeyi birleştiren bir proje yapalım. Bir mağaza zincirine ait satış verilerini okuyacak, temizleyecek, analiz edecek ve sonuçları dosyaya yazacağız.
Adım 1: Veriyi Oluştur ve Oku
Gerçek bir senaryoda CSV dosyasından okursun. Biz örnek veriyi kod ile oluşturuyoruz:
import pandas as pd
import numpy as np
# Örnek satış verisi oluştur
np.random.seed(42) # Tekrarlanabilirlik için
n = 200
veri = {
"tarih": pd.date_range("2024-01-01", periods=n, freq="D"),
"magaza": np.random.choice(["İstanbul", "Ankara", "İzmir"], n),
"kategori": np.random.choice(["Elektronik", "Giyim", "Gıda", "Kozmetik"], n),
"urun_sayisi": np.random.randint(1, 20, n),
"birim_fiyat": np.random.uniform(50, 500, n).round(2),
}
df = pd.DataFrame(veri)
df["toplam_tutar"] = df["urun_sayisi"] * df["birim_fiyat"]
# Gerçekçi olması için bazı değerleri NaN yap
mask = np.random.random(n) < 0.05 # %5 eksik veri
df.loc[mask, "birim_fiyat"] = np.nan
df.loc[mask, "toplam_tutar"] = np.nan
print("=== Veri Seti Özeti ===")
print(f"Boyut: {df.shape}")
df.info()
print(f"\nİlk 5 satır:\n{df.head()}")Adım 2: Veriyi Temizle
# Eksik veri analizi
print("\n=== Eksik Veri ===")
print(df.isna().sum())
# Eksik fiyatları medyan ile doldur (ortalama aykırı değerlere hassas)
medyan_fiyat = df["birim_fiyat"].median()
df["birim_fiyat"] = df["birim_fiyat"].fillna(medyan_fiyat)
# Toplam tutarı yeniden hesapla
df["toplam_tutar"] = df["urun_sayisi"] * df["birim_fiyat"]
# Kontrol
print(f"\nTemizleme sonrası eksik: {df.isna().sum().sum()}")Adım 3: Analiz
# 1. Mağaza bazında toplam satış
print("\n=== Mağaza Bazında Satış ===")
magaza_satis = df.groupby("magaza").agg(
toplam_satis=("toplam_tutar", "sum"),
ortalama_satis=("toplam_tutar", "mean"),
siparis_sayisi=("toplam_tutar", "count")
).round(2)
print(magaza_satis)
# 2. Kategori bazında analiz
print("\n=== Kategori Bazında Satış ===")
kategori_satis = df.groupby("kategori").agg(
toplam_satis=("toplam_tutar", "sum"),
ortalama_birim_fiyat=("birim_fiyat", "mean"),
toplam_urun=("urun_sayisi", "sum")
).round(2)
print(kategori_satis.sort_values("toplam_satis", ascending=False))
# 3. Aylık trend
df["ay"] = df["tarih"].dt.to_period("M")
aylik_satis = df.groupby("ay")["toplam_tutar"].sum()
print(f"\n=== Aylık Satış Trendi ===")
print(aylik_satis)
# 4. Pivot tablo: Mağaza x Kategori
print("\n=== Mağaza-Kategori Pivot ===")
pivot = pd.pivot_table(
df,
values="toplam_tutar",
index="magaza",
columns="kategori",
aggfunc="sum"
).round(2)
print(pivot)
# 5. En yüksek 10 satış
print("\n=== En Yüksek 10 Satış ===")
top10 = df.nlargest(10, "toplam_tutar")[["tarih", "magaza", "kategori", "toplam_tutar"]]
print(top10.to_string(index=False))Adım 4: Sonuçları Kaydet
# Ana veriyi CSV'ye yaz
df.to_csv("satis_temiz.csv", index=False, encoding="utf-8-sig")
# Özet raporu Excel'e yaz (birden fazla sayfa)
with pd.ExcelWriter("satis_raporu.xlsx", engine="openpyxl") as writer:
magaza_satis.to_excel(writer, sheet_name="Mağaza Bazında")
kategori_satis.to_excel(writer, sheet_name="Kategori Bazında")
pivot.to_excel(writer, sheet_name="Pivot Tablo")
print("\n✅ Rapor dosyaları oluşturuldu!")
print(" - satis_temiz.csv")
print(" - satis_raporu.xlsx")Bu proje gerçek dünyada yapacağın veri analizi iş akışını temsil ediyor: oku → keşfet → temizle → analiz et → raporla. pandas bu zincirin her adımında yanında.
10. Yaygın Hatalar ve İpuçları
Hata 1: SettingWithCopyWarning
pandas'ın en kafa karıştırıcı uyarısı. Bir filtrelenmiş DataFrame'e atama yapmaya çalışınca ortaya çıkar:
import pandas as pd
df = pd.DataFrame({
"isim": ["Ali", "Ayşe", "Mehmet"],
"maas": [15000, 18000, 22000]
})
# ❌ Uyarı verebilir
filtreli = df[df["maas"] > 16000]
filtreli["maas"] = filtreli["maas"] * 1.1 # SettingWithCopyWarning!
# ✅ .copy() ile güvenli
filtreli = df[df["maas"] > 16000].copy()
filtreli["maas"] = filtreli["maas"] * 1.1 # Sorunsuz
# ✅ Veya .loc ile doğrudan
df.loc[df["maas"] > 16000, "maas"] *= 1.1 # Orijinal df'i güncellerHata 2: Dtype Karışıklığı
CSV'den okunan sayılar bazen string olarak gelir:
import pandas as pd
# Sorun: "fiyat" sütunu string olarak okunmuş
df = pd.DataFrame({"fiyat": ["100", "200", "300"]})
print(df["fiyat"].dtype) # object (string)
# Çözüm: dönüştür
df["fiyat"] = pd.to_numeric(df["fiyat"], errors="coerce") # Hatalılar NaN olur
print(df["fiyat"].dtype) # float64 veya int64Hata 3: Index Kargaşası
Filtreleme sonrası index'ler atlanır, bu da karışıklığa yol açar:
import pandas as pd
df = pd.DataFrame({"x": [10, 20, 30, 40, 50]})
filtreli = df[df["x"] > 20]
print(filtreli.index.tolist()) # [2, 3, 4] — 0'dan başlamıyor!
# Çözüm: reset_index
filtreli = filtreli.reset_index(drop=True)
print(filtreli.index.tolist()) # [0, 1, 2]Özet
NumPy, Python listelerinden 50-100 kat daha hızlı sayısal hesaplama yapar; pandas'ın altyapısıdır.
pandas Series tek sütun, DataFrame ise çok sütunlu tablo yapısıdır — veri analizinin temel birimleri.
read_csv(),read_json(),read_excel()ile her formattan veri okursun;to_csv(),to_excel()ile yazarsın.Boolean indexing,
.loc[],.iloc[]ve.query()ile veriyi dilediğin gibi filtrelersin.groupby()+agg()vepivot_table()ile verileri gruplayıp özetlersin — SQL'deki GROUP BY'ın karşılığı.Eksik verilerle
isna(),fillna(),dropna()ile başa çıkarsın;merge()veconcat()ile tabloları birleştirirsin.
AI Asistan
Sorularını yanıtlamaya hazır