- Eksik değerleri bulmak ve uygun bir stratejiyle (silme ya da doldurma) ele almak
groupby, adlandırılmış özetleme,transformvepivot_tableile özet tablolar oluşturmak- Tabloları
mergeile doğru birleştirmek ve sonuçtaki satır sayısını önceden bilmek - Tarihlerle çalışıp aylık rapor ve büyüme oranları hesaplamak
Gerçek veri hiçbir zaman ders kitabındaki kadar düzenli değildir: bazı hücreler boştur, bilgi birkaç tabloya dağılmıştır, tarihler metin olarak yazılmıştır. Bir analistin işi dört adımdan oluşur: temizle → birleştir → grupla → yanıtla. Bu derste her adım için pandas araçlarını öğrenecek, sonunda da iki şubesi olan bir kafe zincirinin çeyreklik satışlarını analiz edeceksin.
Eksik değerler
pandas eksik bir değeri NaN (Not a Number) olarak gösterir. isna().sum() her sütundaki boşlukları sayar. count() yalnızca dolu değerleri, size ise tüm satırları sayar. mean, sum, std gibi fonksiyonlar NaN değerlerini varsayılan olarak atlar. Sonra seçim yaparız: dropna() boşluk içeren satırları siler, fillna() ise onları doldurur: bir sabitle, medyanla ya da ortalamayla.
import numpy as np
import pandas as pd
df = pd.DataFrame({
'student': ['Aysel', 'Murad', 'Leyla', 'Elvin', 'Nigar'],
'group': ['A', 'B', 'A', 'B', 'A'],
'math': [91, np.nan, 85, 64, np.nan],
'physics': [88, 72, np.nan, 70, 81],
})
print(df.isna().sum())
print(df['math'].mean(), df['math'].count())
print(df.dropna().shape)
filled = df.fillna({'math': df['math'].median(), 'physics': df['physics'].mean()})
print(filled)
print(np.nan == np.nan)▸ Beklenen çıktı
student 0 group 0 math 2 physics 1 dtype: int64 80.0 3 (2, 4) student group math physics 0 Aysel A 91.0 88.00 1 Murad B 85.0 72.00 2 Leyla A 85.0 77.75 3 Elvin B 64.0 70.00 4 Nigar A 85.0 81.00 False
dropna() 5 satırdan sadece 2'sini bıraktı; bilginin çoğu kayboldu.Gruplama: böl, uygula, birleştir
groupby, tabloyu bir anahtar sütunun değerlerine göre gruplara böler, her gruba bir fonksiyon (toplam, ortalama, sayı) uygular ve sonuçları yeni bir tabloda birleştirir. SQL'deki GROUP BY ile aynı fikirdir.
agg ile aynı anda birkaç göstergeyi hesaplarız; adlandırılmış özetleme ad=('sütun', 'fonksiyon') sonuç sütunlarına anlaşılır adlar verir. İki anahtarla gruplama çok düzeyli bir indeks (MultiIndex) oluşturur. transform ise sonucu asıl tablonun her satırına geri döndürür; örneğin her satışın kendi şubesinin gelirindeki payını bulmak için.
import pandas as pd
df = pd.DataFrame({
'store': ['Baku', 'Baku', 'Ganja', 'Baku', 'Ganja', 'Ganja', 'Baku'],
'category': ['Food', 'Drinks', 'Food', 'Food', 'Drinks', 'Food', 'Drinks'],
'amount': [120.0, 45.5, 80.0, 99.5, 30.0, 64.0, 52.0],
})
print(df.groupby('store')['amount'].sum())
summary = df.groupby('store').agg(
total=('amount', 'sum'),
average=('amount', 'mean'),
orders=('amount', 'size'),
)
print(summary.round(2))
print(df.groupby(['store', 'category'])['amount'].sum())
df['share'] = (df['amount'] / df.groupby('store')['amount'].transform('sum')).round(3)
print(df.head(3))▸ Beklenen çıktı
store
Baku 317.0
Ganja 174.0
Name: amount, dtype: float64
total average orders
store
Baku 317.0 79.25 4
Ganja 174.0 58.00 3
store category
Baku Drinks 97.5
Food 219.5
Ganja Drinks 30.0
Food 144.0
Name: amount, dtype: float64
store category amount share
0 Baku Food 120.0 0.379
1 Baku Drinks 45.5 0.144
2 Ganja Food 80.0 0.460- xᵢi. grubun ortalaması (örneğin ortalama fiş tutarı)
- wᵢgrubun ağırlığı: genellikle gözlem sayısı
Ağırlıklı ortalama. pandas'ta: np.average(x, weights=w) ya da yalnızca genel toplamı genel sayıya bölmek.
Bakü şubesinde 300 fiş var, ortalama fiş 8 manat; Gence şubesinde 100 fiş var, ortalama fiş 12 manat. Tüm zincirin ortalama fişi nedir?
Çözümü gösterÇözümü gizle
Doğru yol: toplam gelir = 300 · 8 + 100 · 12 = 2400 + 1200 = 3600 manat, 400 fiş.
x̄_w = 3600 / 400 = 9 manat.
pandas'ta bir
groupby(...).mean() sonucunun yeniden ortalamasını alma; ya asıl satırlar üzerinde mean() kullan ya da toplamları birbirine böl.Tabloları birleştirmek: merge
Siparişler bir tabloda, müşteriler başka bir tabloda; onları ortak bir anahtar sütunla (customer_id) birleştiririz. how parametresi, anahtarı yalnızca bir tabloda bulunan satırlara ne olacağını belirler. indicator=True, her satırın nereden geldiğini gösteren bir _merge sütunu ekler.
| how | Sonuçta hangi anahtarlar kalır |
|---|---|
inner | yalnızca iki tabloda da bulunanlar (varsayılan) |
left | sol tablonun tüm anahtarları; sağda bulunamayanlar NaN olur |
right | sağ tablonun tüm anahtarları |
outer | iki tablonun tüm anahtarları |
import pandas as pd
orders = pd.DataFrame({'order_id': [1, 2, 3, 4],
'customer_id': [10, 11, 10, 13],
'amount': [25.0, 40.0, 15.5, 60.0]})
customers = pd.DataFrame({'customer_id': [10, 11, 12],
'name': ['Aysel', 'Murad', 'Leyla']})
inner = orders.merge(customers, on='customer_id')
print(inner)
left = orders.merge(customers, on='customer_id', how='left')
print(left[['order_id', 'name']])
outer = orders.merge(customers, on='customer_id', how='outer', indicator=True)
print(outer[['customer_id', 'order_id', 'name', '_merge']])▸ Beklenen çıktı
order_id customer_id amount name 0 1 10 25.0 Aysel 1 2 11 40.0 Murad 2 3 10 15.5 Aysel order_id name 0 1 Aysel 1 2 Murad 2 3 Aysel 3 4 NaN customer_id order_id name _merge 0 10 1.0 Aysel both 1 10 3.0 Aysel both 2 11 2.0 Murad both 3 12 NaN Leyla right_only 4 13 4.0 NaN left_only
outer sonucunda order_id ondalıklı sayıya dönüştü, çünkü tam sayı sütunu NaN tutamaz.a) Yukarıdaki orders (4 satır) ve customers (3 satır) için inner, left ve outer birleştirmelerinde satır sayısını önceden bul. b) Bir anahtar sol tabloda 3, sağ tabloda 2 kez geçiyorsa inner birleştirme bu anahtar için kaç satır verir?
Çözümü gösterÇözümü gizle
inner = 3.left tüm siparişleri korur: 4 (13 numaralı müşteri için ad NaN).outer = 4 + Leyla (12) = 5.b) Her sol satır her sağ satırla eşleşir: 3 · 2 = 6 satır. Bu “çoktan çoğa” patlamasıdır; tablo beklenmedik biçimde büyür ve toplamlar iki kez sayılır.
pivot_table, map, apply ve tarihler
pivot_table, Excel'deki özet tablonun aynısıdır: index satırları, columns sütunları, values ve aggfunc ise hücrelerde neyin hesaplanacağını belirler. fill_value=0 boş hücreleri doldurur, margins=True ise “All” adlı toplam satırı ve sütunu ekler.
import pandas as pd
df = pd.DataFrame({
'store': ['Baku', 'Baku', 'Ganja', 'Baku', 'Ganja', 'Ganja', 'Baku'],
'category': ['Food', 'Drinks', 'Food', 'Food', 'Drinks', 'Food', 'Drinks'],
'amount': [120.0, 45.5, 80.0, 99.5, 30.0, 64.0, 52.0],
})
pt = df.pivot_table(index='store', columns='category', values='amount',
aggfunc='sum', fill_value=0, margins=True)
print(pt)
print(df.pivot_table(index='store', columns='category', values='amount', aggfunc='count'))▸ Beklenen çıktı
category Drinks Food All store Baku 97.5 219.5 317.0 Ganja 30.0 144.0 174.0 All 127.5 363.5 491.0 category Drinks Food store Baku 2 2 Ganja 1 2
Bir sütunu dönüştürmenin üç yolu vardır: map değerleri bir sözlüğe göre değiştirir, apply her elemana istenen bir fonksiyonu uygular, pd.cut ise sayıları aralıklara (kutulara) ayırır.
import numpy as np
import pandas as pd
df = pd.DataFrame({'code': ['BAK', 'GNJ', 'SMQ', 'BAK'], 'amount': [120.0, 45.5, 80.0, 30.0]})
df['city'] = df['code'].map({'BAK': 'Baku', 'GNJ': 'Ganja', 'SMQ': 'Sumgait'})
df['size_apply'] = df['amount'].apply(lambda x: 'large' if x >= 60 else 'small')
df['size_where'] = np.where(df['amount'] >= 60, 'large', 'small')
df['band'] = pd.cut(df['amount'], bins=[0, 50, 100, 200], labels=['low', 'mid', 'high'])
print(df)
print((df['size_apply'] == df['size_where']).all())▸ Beklenen çıktı
code amount city size_apply size_where band 0 BAK 120.0 Baku large large high 1 GNJ 45.5 Ganja small small low 2 SMQ 80.0 Sumgait large large mid 3 BAK 30.0 Baku small small low True
Metin olarak saklanan tarihleri pd.to_datetime ile (ya da read_csv(..., parse_dates=['date']) ile) gerçek tarihlere çeviririz. Sonra .dt üzerinden yıl, ay ve haftanın günü alınır; to_period('M') ise tarihi ayına “yuvarlar”. İki tarihin farkı bir Timedelta'dır.
import pandas as pd
sales = pd.DataFrame({
'date': ['2026-01-15', '2026-01-28', '2026-02-03', '2026-02-20', '2026-03-05', '2026-03-18'],
'amount': [310.0, 275.5, 402.0, 350.0, 390.0, 441.5],
})
sales['date'] = pd.to_datetime(sales['date'])
sales['month'] = sales['date'].dt.to_period('M')
sales['weekday'] = sales['date'].dt.day_name()
print(sales)
print(sales.groupby('month')['amount'].sum())
print((sales['date'].max() - sales['date'].min()).days, 'days')▸ Beklenen çıktı
date amount month weekday 0 2026-01-15 310.0 2026-01 Thursday 1 2026-01-28 275.5 2026-01 Wednesday 2 2026-02-03 402.0 2026-02 Tuesday 3 2026-02-20 350.0 2026-02 Friday 4 2026-03-05 390.0 2026-03 Thursday 5 2026-03-18 441.5 2026-03 Wednesday month 2026-01 585.5 2026-02 752.0 2026-03 831.5 Freq: M, Name: amount, dtype: float64 62 days
Mini analiz: bir kafe zincirinin satışları
Bir kafe zincirinin Bakü ve Gence'de şubeleri var. Satış kaydında tarih, şube, ürün kodu ve adet; ayrı bir tabloda ise ürün adları ve manat cinsinden fiyatlar tutuluyor (veriler uydurmadır). Yönetim soruyor: her şube her ay ne kadar gelir getirdi, toplam gelir nasıl değişti ve hangi ürün önde?
- 1Oku
Kaydı
read_csvile oku ve tarihleriparse_datesile hemen dönüştür. - 2Birleştir
Ürünler tablosunu
how='left'vevalidate='many_to_one'ile ekle. - 3Hesapla
Gelir = adet · fiyat; tarihten ayı çıkar.
- 4Özetle
pivot_tableile ay × şube tablosu oluştur, toplamı ve büyüme oranını ekle, ürünleri gelire göre sırala.
- xₜmevcut dönemin değeri
- xₜ₋₁önceki dönemin değeri
Büyüme oranı; pandas'ta pct_change() bunu hesaplar (100 ile çarpmadan). İlk dönemin önceki değeri olmadığı için NaN çıkar.
import io
import pandas as pd
sales_csv = '''date,store,product_id,qty
2026-01-05,Baku,1,30
2026-01-12,Ganja,2,25
2026-01-20,Baku,3,12
2026-02-02,Baku,1,34
2026-02-14,Ganja,3,18
2026-02-25,Ganja,1,20
2026-03-03,Baku,2,41
2026-03-15,Ganja,2,28
2026-03-28,Baku,3,15'''
products = pd.DataFrame({'product_id': [1, 2, 3], 'product': ['Tea', 'Coffee', 'Cake'],
'price': [4.5, 6.0, 12.0]})
sales = pd.read_csv(io.StringIO(sales_csv), parse_dates=['date'])
df = sales.merge(products, on='product_id', how='left', validate='many_to_one')
df['revenue'] = df['qty'] * df['price']
df['month'] = df['date'].dt.month
report = df.pivot_table(index='month', columns='store', values='revenue',
aggfunc='sum', fill_value=0)
report['total'] = report.sum(axis=1)
report['growth_%'] = report['total'].pct_change().mul(100).round(1)
print(report)
print(df.groupby('product')['revenue'].sum().sort_values(ascending=False))▸ Beklenen çıktı
store Baku Ganja total growth_% month 1 279.0 150.0 429.0 NaN 2 153.0 306.0 459.0 7.0 3 426.0 168.0 594.0 29.4 product Coffee 564.0 Cake 540.0 Tea 378.0 Name: revenue, dtype: float64
Bulgular: çeyrek boyunca toplam gelir 429 manattan 594 manata çıktı, martta büyüme %29,4 oldu; bu, esas olarak Bakü şubesindeki kahve ve pasta satışları sayesinde. Şubatta Gence, Bakü'yü geçti çünkü orada pastalar iyi sattı. Çeyreğin lider ürünü kahve (564 manat). Çay gelirde sonuncu (378 manat): 84 bardak satıldı ama fiyatı düşük; oysa yalnızca 45 pasta 540 manat getirdi. Tek bir tablo ve birkaç satır kod yönetime somut kararlar için bir temel sağladı.
Harcamalar tablosuna göre ayrı satırlarda yazdır: 1) her kişinin toplam harcamasını sözlük olarak (to_dict()); 2) toplamı en büyük olan kategoriyi; 3) her kişinin harcama sayısını sözlük olarak.
import pandas as pd
expenses = pd.DataFrame({
'person': ['Aysel', 'Murad', 'Aysel', 'Leyla', 'Murad', 'Aysel', 'Leyla'],
'category': ['food', 'transport', 'books', 'food', 'food', 'food', 'books'],
'amount': [12.5, 3.0, 25.0, 18.0, 9.5, 7.0, 14.0],
})
# 1) total per person (dict)
# 2) category with the largest total
# 3) number of expenses per person (dict)▸ Beklenen çıktı
{'Aysel': 44.5, 'Leyla': 32.0, 'Murad': 12.5}
food
{'Aysel': 3, 'Leyla': 2, 'Murad': 2}Siparişleri müşterilerle how='left' kullanarak birleştir ve bulunamayan şehirleri 'Unknown' ile doldur. Sonra yazdır: 1) şehirlere göre sipariş tutarlarının toplamını sözlük olarak; 2) Bakü'nün toplam tutardaki payını yüzde olarak, 1 ondalık basamağa yuvarlanmış.
import pandas as pd
orders = pd.DataFrame({'order_id': [1, 2, 3, 4, 5], 'customer_id': [1, 2, 1, 3, 4],
'amount': [30.0, 45.0, 20.0, 15.0, 50.0]})
customers = pd.DataFrame({'customer_id': [1, 2, 3], 'city': ['Baku', 'Ganja', 'Baku']})
# merge, fill missing cities, then print the two results▸ Beklenen çıktı
{'Baku': 65.0, 'Ganja': 45.0, 'Unknown': 50.0}
40.6Önemli noktalar
isna().sum()boşlukları sayar;dropnasiler,fillnadoldurur;NaN == NaNFalseverir.groupby+aggböl–uygula–birleştir şemasını uygular;transformsonucu her satıra geri verir.- Grup ortalamalarını birleştirirken ağırlıklı ortalamayı kullan: ∑ wᵢxᵢ / ∑ wᵢ.
mergeiçinhow(inner, left, right, outer) sonucu belirler; tekrarlanan anahtarlar satırları çoğaltır,validateile kontrol et.pivot_table, Excel'in özet tablosudur; mümkün olduğundaapplyyerine vektörel işlemleri seç.- Tarihleri
to_datetimeya daparse_datesile dönüştür, sonra dönemleri.dtvepct_changeile analiz et.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
s = pd.Series([4, np.nan, 8]) için s.mean() ve s.count() nedir?