Məzmuna keç
Educora
Universitet25 dəq32 / 42

pandas ilə verilənlərin analizi

Real verilənlərlə işləməyin əsas alətləri: buraxılmış qiymətlər, `groupby` və `agg`, cədvəllərin `merge` ilə birləşdirilməsi, `pivot_table`, `map` və `apply`, tarixlər və kafe şəbəkəsinin satışlarının mini analizi.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Buraxılmış qiymətləri tapmaq və vəziyyətə uyğun strategiya ilə (silmək, doldurmaq) aradan qaldırmaq
  • groupby, adlı aqreqasiya, transform və pivot_table ilə xülasə cədvəlləri qurmaq
  • Cədvəlləri merge ilə 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ə.

Python
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
Riyaziyyatın ortası 80-dir, çünki yalnız 3 dolu qiymət nəzərə alınır. 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

Tərif
Böl–tətbiq et–birləşdir (split–apply–combine)

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.

Python
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̄_w = ∑ wᵢ · xᵢ / ∑ wᵢx̄_w = ∑ wᵢ · xᵢ / ∑ wᵢ
burada:
  • 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.

Nümunə 1: ortaların ortası tələsi

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ər
Səhv yol: (8 + 12) / 2 = 10 manat — filiallar bərabər çəkili sayılır.
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.

howNəticədə hansı açarlar qalır
inneryalnız hər iki cədvəldə olanlar (susmaya görə)
leftsol cədvəlin bütün açarları; sağda tapılmayanlar NaN
rightsağ cədvəlin bütün açarları
outerhər iki cədvəlin bütün açarları
Python
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
13 nömrəli müştəri müştərilər cədvəlində yoxdur, Leylanın (12) isə sifarişi yoxdur. outer nəticəsində order_id kəsr ədədə çevrildi, çünki tam ədəd sütununda NaN saxlamaq olmur.
Nümunə 2: nəticədə neçə sətir olacaq?

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ər
a) Açar 10 → 2 sifariş · 1 müştəri = 2 sətir, açar 11 → 1 sətir: 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.

Python
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.

Python
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.

Python
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?

  1. 1
    Oxu

    read_csv ilə jurnalı oxu, parse_dates ilə tarixləri dərhal çevir.

  2. 2
    Birləşdir

    Məhsullar cədvəlini how='left' və validate='many_to_one' ilə qoş.

  3. 3
    Hesabla

    Gəlir = say · qiymət; tarixdən ayı çıxar.

  4. 4
    Xülasə et

    pivot_table ilə ay × filial cədvəli qur, ümumi gəliri və artım faizini əlavə et, məhsulları gəlirə görə sırala.

Δ% = (xₜ − xₜ₋₁) / xₜ₋₁ · 100%Δ% = (xₜ − xₜ₋₁) / xₜ₋₁ · 100%
burada:
  • 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.

Python
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.

Tapşırıq

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.

Tapşırıq · Python
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}
Tapşırıq

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ış.

Tapşırıq · Python
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; dropna onları silir, fillna isə doldurur; NaN == NaN ifadəsi False verir.
  • groupby + agg böl–tətbiq et–birləşdir sxemini həyata keçirir; transform nəticəni hər sətrə qaytarır.
  • Qrupların ortasını birləşdirəndə çəkili ortadan istifadə et: ∑ wᵢxᵢ / ∑ wᵢ.
  • merge üçün how (inner, left, right, outer) nəticəni təyin edir; təkrarlanan açarlar sətirləri çoxaldır — validate ilə yoxla.
  • pivot_table Excel-in pivot cədvəlidir; apply əvəzinə mümkün olanda vektor əməliyyatları seç.
  • Tarixləri to_datetime və ya parse_dates ilə çevir, sonra .dt və pct_change ilə dövrləri təhlil et.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
s = pd.Series([4, np.nan, 8]) üçün s.mean() və s.count() nəyə bərabərdir?