- Buraxılmış qiymətləri tapmaq və vəziyyətə uyğun strategiya ilə (silmək, doldurmaq) aradan qaldırmaq
groupby, adlı aqreqasiya,transformvəpivot_tableilə xülasə cədvəlləri qurmaq- Cədvəlləri
mergeilə düzgün birləşdirmək və nəticədəki sətirlərin sayını əvvəlcədən bilmək - Tarixlərlə işləyib aylıq hesabat və artım faizi hesablamaq
Real verilənlər heç vaxt dərslikdəki kimi səliqəli olmur: bəzi xanalar boşdur, məlumat bir neçə cədvələ paylanıb, tarixlər mətn kimi yazılıb. Analitikin işi dörd addımdan ibarətdir: təmizlə → birləşdir → qruplaşdır → cavab ver. Bu dərsdə hər addım üçün pandas alətlərini öyrənəcək, sonda isə iki filialı olan kafe şəbəkəsinin rüblük satışlarını təhlil edəcəksən.
Buraxılmış qiymətlər
pandas buraxılmış qiyməti NaN (Not a Number) kimi göstərir. isna().sum() hər sütunda neçə boşluq olduğunu sayır. count() yalnız dolu qiymətləri, size isə bütün sətirləri sayır. mean, sum, std kimi funksiyalar NaN-ları susmaya görə keçir. Sonra seçim edirik: dropna() boşluğu olan sətirləri silir, fillna() isə onları doldurur — sabitlə, median və ya orta ilə.
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)▸ Gözlənilən nəticə
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 sətirdən cəmi 2-ni saxladı — məlumatın çoxu itdi.Qruplaşdırma: böl, tətbiq et, birləşdir
groupby cədvəli açar sütunun qiymətlərinə görə qruplara bölür, hər qrupa funksiya (cəm, orta, say) tətbiq edir və nəticələri yeni cədvəldə birləşdirir. SQL-dəki GROUP BY ilə eyni ideyadır.
agg ilə bir dəfəyə bir neçə göstərici hesablayırıq; adlı aqreqasiya ad=('sütun', 'funksiya') nəticə sütunlarına aydın adlar verir. İki açarla qruplaşdırma çoxsəviyyəli indeks (MultiIndex) yaradır. transform isə nəticəni ilkin cədvəlin hər sətrinə qaytarır — məsələn, hər satışın öz filialının gəlirindəki payını tapmaq üçün.
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))▸ Gözlənilən nəticə
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-ci qrupun ortası (məsələn, orta çek)
- wᵢqrupun çəkisi — adətən müşahidələrin sayı
Çəkili orta. pandas-da: np.average(x, weights=w) və ya sadəcə ümumi cəmi ümumi saya bölmək.
Bakı filialında 300 çek, orta çek 8 manat; Gəncə filialında 100 çek, orta çek 12 manatdır. Bütün şəbəkə üzrə orta çek nə qədərdir?
Həllini göstərHəllini gizlət
Düzgün yol: ümumi gəlir = 300 · 8 + 100 · 12 = 2400 + 1200 = 3600 manat, çeklər 400.
x̄_w = 3600 / 400 = 9 manat.
pandas-da
groupby(...).mean() nəticəsinin yenidən ortasını götürmə — ya ilkin sətirlər üzrə mean(), ya da cəmlərin nisbətini hesabla.Cədvəlləri birləşdirmək: merge
Sifarişlər bir cədvəldə, müştərilər digərindədir; onları ortaq açar sütunla (customer_id) birləşdiririk. how parametri açarı yalnız bir cədvəldə olan sətirlərlə nə edəcəyini təyin edir. indicator=True hər sətrin haradan gəldiyini göstərən _merge sütunu əlavə edir.
| how | Nəticədə hansı açarlar qalır |
|---|---|
inner | yalnız hər iki cədvəldə olanlar (susmaya görə) |
left | sol cədvəlin bütün açarları; sağda tapılmayanlar NaN |
right | sağ cədvəlin bütün açarları |
outer | hər iki cədvəlin bütün açarları |
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']])▸ Gözlənilən nəticə
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 nəticəsində order_id kəsr ədədə çevrildi, çünki tam ədəd sütununda NaN saxlamaq olmur.a) Yuxarıdakı orders (4 sətir) və customers (3 sətir) üçün inner, left və outer birləşmələrində sətirlərin sayını əvvəlcədən tap. b) Sol cədvəldə açar 3 dəfə, sağ cədvəldə 2 dəfə təkrarlanırsa, inner birləşmə bu açar üçün neçə sətir verər?
Həllini göstərHəllini gizlət
inner = 3.left bütün sifarişləri saxlayır: 4 (13 nömrəli müştəri üçün ad NaN).outer = 4 + Leyla (12) = 5.b) Hər sol sətir hər sağ sətirlə cütləşir: 3 · 2 = 6 sətir. Bu «çoxdan-çoxa» partlayışıdır — gözlənilmədən cədvəl böyüyür və cəmlər ikiqat sayılır.
pivot_table, map, apply və tarixlər
pivot_table Excel-dəki pivot cədvəlin (PivotTable) eynisidir: index sətirləri, columns sütunları, values və aggfunc isə xanalarda nəyin hesablanacağını təyin edir. fill_value=0 boş xanaları doldurur, margins=True isə «All» adlı yekun sətir və sütun əlavə edir.
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'))▸ Gözlənilən nəticə
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
Sütunu çevirmək üçün üç yol var: map qiymətləri lüğətə görə əvəz edir, apply hər elementə istənilən funksiyanı tətbiq edir, pd.cut isə ədədləri intervallara (səbətlərə) bölü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())▸ Gözlənilən nəticə
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
Mətn kimi saxlanan tarixləri pd.to_datetime ilə (və ya read_csv(..., parse_dates=['date']) ilə) əsl tarixə çeviririk. Sonra .dt vasitəsilə il, ay, həftənin günü alınır, to_period('M') isə tarixi aya «yuvarlaqlaşdırır». İki tarixin fərqi 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')▸ Gözlənilən nəticə
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: kafe şəbəkəsinin satışları
Kafe şəbəkəsinin Bakı və Gəncədə filialları var. Satışlar jurnalında tarix, filial, məhsulun kodu və say, ayrıca cədvəldə isə məhsulların adı və manatla qiyməti saxlanır (verilənlər uydurmadır). Rəhbərlik soruşur: hər ay hər filial nə qədər gəlir gətirib, ümumi gəlir necə dəyişib və hansı məhsul liderdir?
- 1Oxu
read_csvilə jurnalı oxu,parse_datesilə tarixləri dərhal çevir. - 2Birləşdir
Məhsullar cədvəlini
how='left'vəvalidate='many_to_one'ilə qoş. - 3Hesabla
Gəlir = say · qiymət; tarixdən ayı çıxar.
- 4Xülasə et
pivot_tableilə ay × filial cədvəli qur, ümumi gəliri və artım faizini əlavə et, məhsulları gəlirə görə sırala.
- xₜcari dövrün göstəricisi
- xₜ₋₁əvvəlki dövrün göstəricisi
Artım tempi; pandas-da pct_change() bunu hesablayır (100-ə vurmadan). Birinci dövr üçün əvvəlki qiymət yoxdur, ona görə NaN alınır.
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))▸ Gözlənilən nəticə
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
Nəticələr: rüb ərzində ümumi gəlir 429 manatdan 594 manata qalxıb, martda artım 29,4% olub — əsasən Bakı filialının qəhvə və tort satışları hesabına. Fevralda Gəncə Bakını keçib, çünki orada tortlar yaxşı satılıb. Rüb üzrə lider məhsul qəhvədir (564 manat). Çay gəlirdə sonuncudur (378 manat): 84 stəkan satılıb, amma qiyməti aşağıdır, halbuki cəmi 45 tort 540 manat gətirib. Bir cədvəl və bir neçə sətir kod rəhbərliyə konkret qərarlar üçün əsas verdi.
Xərclər cədvəlinə görə ayrı sətirlərdə çap et: 1) hər adamın ümumi xərcini lüğət kimi (to_dict()); 2) ümumi məbləği ən böyük olan kateqoriyanı; 3) hər adamın xərclərinin sayını lüğət kimi.
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)▸ Gözlənilən nəticə
{'Aysel': 44.5, 'Leyla': 32.0, 'Murad': 12.5}
food
{'Aysel': 3, 'Leyla': 2, 'Murad': 2}Sifarişləri müştərilərlə how='left' ilə birləşdir, tapılmayan şəhərləri 'Unknown' ilə doldur. Sonra çap et: 1) şəhərlər üzrə sifariş məbləğlərinin cəmini lüğət kimi; 2) Bakının ümumi məbləğdəki payını faizlə, 1 onluq rəqəmə qədər yuvarlaqlaşdırılmış.
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▸ Gözlənilən nəticə
{'Baku': 65.0, 'Ganja': 45.0, 'Unknown': 50.0}
40.6Əsas fikirlər
isna().sum()boşluqları sayır;dropnaonları silir,fillnaisə doldurur;NaN == NaNifadəsiFalseverir.groupby+aggböl–tətbiq et–birləşdir sxemini həyata keçirir;transformnəticəni hər sətrə qaytarır.- Qrupların ortasını birləşdirəndə çəkili ortadan istifadə et: ∑ wᵢxᵢ / ∑ wᵢ.
mergeüçünhow(inner, left, right, outer) nəticəni təyin edir; təkrarlanan açarlar sətirləri çoxaldır —validateilə yoxla.pivot_tableExcel-in pivot cədvəlidir;applyəvəzinə mümkün olanda vektor əməliyyatları seç.- Tarixləri
to_datetimevə yaparse_datesilə çevir, sonra.dtvəpct_changeilə dövrləri təhlil et.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
s = pd.Series([4, np.nan, 8]) üçün s.mean() və s.count() nəyə bərabərdir?