groupby: guruhlab hisoblash
Sahna: "har filial bo'yicha"
Do'kon tarmog'ining bir yillik savdosi — 11 mingdan ortiq qator, har biri chekdagi bitta mahsulot. Rahbar uchun bu qatorlarning o'zi foydasiz. Unga xulosa kerak: har filial qancha topdi? Qaysi to'lov turi ko'proq? Qaysi oy kuchli? Har bir savol bir xil shaklda: "har ... bo'yicha ... ning yig'indisi/o'rtachasi". Bu — groupby.
import numpy as np import pandas as pd savdo = pd.read_csv(DATA / "dokon_savdo.csv", parse_dates=["sana"], date_format="%d.%m.%Y") savdo["tushum"] = savdo["miqdor"] * savdo["narx"] print(savdo.shape) savdo.head()
(11352, 9)
| chek_id | sana | vaqt | filial_id | mahsulot_id | miqdor | narx | tolov | tushum | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 500001 | 2025-01-01 00:00:00 | 10:25 | 1 | 9 | 1 | 4000 | Click | 4000 |
| 1 | 500002 | 2025-01-01 00:00:00 | 13:37 | 1 | 4 | 4 | 18000 | naqd | 72000 |
| 2 | 500002 | 2025-01-01 00:00:00 | 13:37 | 1 | 1 | 4 | 5000 | naqd | 20000 |
| 3 | 500002 | 2025-01-01 00:00:00 | 13:37 | 1 | 2 | 1 | 12000 | naqd | 12000 |
| 4 | 500003 | 2025-01-01 00:00:00 | 11:05 | 1 | 10 | 1 | 62000 | karta | 62000 |
tushum — har qatorning puli: dona × narx.
Bo'lish, hisoblash, birlashtirish

groupby: qatorlar guruhlarga bo'linadi, har guruh bitta songa yig'iladi, natijalar birlashadi
savdo.groupby("filial_id")["tushum"].sum()
| filial_id | tushum |
|---|---|
| 1 | 139529000 |
| 2 | 133251000 |
| 3 | 127296000 |
| 4 | 128358000 |
| 5 | 35842000 |
Uch qadam, bitta qator:
- Bo'lish (split): qatorlar
filial_idqiymati bo'yicha guruhlarga ajratildi. - Hisoblash (apply): har guruhning
tushumustunigasumqo'llandi. - Birlashtirish (combine): natijalar bitta Series bo'ldi; guruh nomlari — index.
5-filial boshqalardan ancha kam topgan — 15-bobda sababini topamiz.
Bir nechta hisob birdan: agg
hisobot = savdo.groupby("filial_id").agg( qatorlar=("chek_id", "size"), cheklar=("chek_id", "nunique"), tushum=("tushum", "sum"), ortacha_qator=("tushum", "mean"), ) hisobot
| filial_id | qatorlar | cheklar | tushum | ortacha_qator |
|---|---|---|---|---|
| 1 | 2754 | 1368 | 139529000 | 50664.125 |
| 2 | 2658 | 1330 | 133251000 | 50132.054 |
| 3 | 2597 | 1318 | 127296000 | 49016.558 |
| 4 | 2609 | 1309 | 128358000 | 49198.16 |
| 5 | 734 | 362 | 35842000 | 48831.063 |
Named aggregation: yangi_nom=("ustun", "funksiya"). Natija jadvalining ustunlari darhol tushunarli nomli.
size va nunique farqiga qarang: bitta chekda 1–3 mahsulot bo'ladi, shuning uchun qatorlar soni cheklar sonidan ko'p. size — qatorlar, nunique — noyob cheklar.
Fikrlash tuzog'i: "o'rtacha chek"
Rahbar so'raydi: "o'rtacha chek qancha?" Yuqoridagi ortacha_qator — javob emas: bu bitta mahsulot qatorining o'rtachasi. Chek esa bir nechta qatordan iborat. To'g'ri yo'l — ikki bosqichli guruhlash: avval har chekning jamini topamiz, keyin cheklar o'rtachasini.
cheklar = savdo.groupby(["filial_id", "chek_id"])["tushum"].sum() ortacha_chek = cheklar.groupby("filial_id").mean() taqqos = pd.DataFrame({"qator o'rtachasi": hisobot["ortacha_qator"], "chek o'rtachasi": ortacha_chek}).round(0) print(taqqos.to_string())
qator o'rtachasi chek o'rtachasi filial_id 1 50664.0 101995.0 2 50132.0 100189.0 3 49017.0 96583.0 4 49198.0 98058.0 5 48831.0 99011.0
Farq — taxminan ikki barobar. Birinchisi bilan hisobot berilsa, rahbar xaridorlar kam xarid qilyapti deb noto'g'ri qaror chiqaradi. groupby — mexanik asbob; nimani guruhlash kerakligini esa savol aytadi.
Ikki kalit bo'yicha: unstack
tolov_filial = savdo.groupby(["filial_id", "tolov"])["tushum"].sum().div(1e6).round(1) print(tolov_filial.head(4)) jadval = tolov_filial.unstack("tolov") jadval
filial_id tolov
1 Click 31.5
Payme 19.0
karta 41.4
naqd 47.6
Name: tushum, dtype: float64
| filial_id | Click | Payme | karta | naqd |
|---|---|---|---|---|
| 1 | 31.5 | 19 | 41.4 | 47.6 |
| 2 | 28.2 | 21.2 | 40.3 | 43.6 |
| 3 | 24.6 | 17.8 | 42.4 | 42.5 |
| 4 | 29.4 | 18.7 | 37.3 | 42.9 |
| 5 | 6.8 | 5.2 | 11.7 | 12.2 |
Ikki kalit — ikki darajali index. unstack("tolov") ichki darajani ustunlarga "yoyadi": endi o'qilishi oson jadval — qatorlar filiallar, ustunlar to'lov turlari.
ax = jadval.plot(kind="bar", stacked=True, rot=0, figsize=(8, 3.6), title="Filial va to'lov turi bo'yicha tushum, mln so'm") ax.set_xlabel("filial") plt.show()

transform: natija har qatorga
agg har guruhga bitta son beradi. Ba'zan esa natija har qatorga qaytishi kerak — masalan, har mahsulot qatorining o'z chekidagi ulushi:
savdo["chek_jami"] = savdo.groupby("chek_id")["tushum"].transform("sum") savdo["chekdagi_ulush"] = (savdo["tushum"] / savdo["chek_jami"]).round(2) savdo.loc[savdo["chek_id"] == savdo["chek_id"].iloc[1], ["chek_id", "mahsulot_id", "tushum", "chek_jami", "chekdagi_ulush"]]
| chek_id | mahsulot_id | tushum | chek_jami | chekdagi_ulush | |
|---|---|---|---|---|---|
| 1 | 500002 | 4 | 72000 | 104000 | 0.69 |
| 2 | 500002 | 1 | 20000 | 104000 | 0.19 |
| 3 | 500002 | 2 | 12000 | 104000 | 0.12 |
transform("sum") — xuddi sum, lekin natija asl jadval uzunligida: chekning har qatoriga o'sha chekning jami yozildi. 12-bobda bo'sh probeglarni to'ldirishda aynan shuni ishlatgan edik.
crosstab: nechta marta
ulush = pd.crosstab(savdo["tolov"], savdo["filial_id"], normalize="columns").mul(100).round(1) ulush
| tolov | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| Click | 22 | 21.4 | 20.4 | 21.4 | 18.9 |
| Payme | 14.7 | 16.7 | 14.4 | 14.8 | 15.9 |
| karta | 29.3 | 29.8 | 32.3 | 28.6 | 30.7 |
| naqd | 34 | 32.1 | 32.8 | 35.2 | 34.5 |
crosstab — ikki ustun juftliklari necha marta uchraganini sanaydi. normalize="columns" — har ustun (filial) ichida foiz: har filialda to'lovlarning qancha qismi naqd, qanchasi karta. Ustun yig'indisi — 100.
pivot_table: Excel dagi "svodnaya"
savdo["oy"] = savdo["sana"].dt.month oylik = savdo.pivot_table(index="oy", columns="filial_id", values="tushum", aggfunc="sum").div(1e6).round(1) oylik.tail(4)
| oy | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 9 | 11.2 | 10 | 10.8 | 13.9 | NaN |
| 10 | 13.6 | 12.8 | 12 | 10.1 | 10.8 |
| 11 | 10.1 | 11.3 | 9.6 | 10.8 | 10.3 |
| 12 | 16.3 | 12 | 13.9 | 15.1 | 14.7 |
pivot_table — groupby + unstack bitta buyruqda: index — qatorlar, columns — ustunlar, values — nima hisoblanadi, aggfunc — qanday. 5-filial ustunida 1–9 oylarda NaN — u oktyabrda ochilgan, avval savdosi yo'q edi. NaN bu yerda "nol" emas, "yo'q edi" degani — farqni yo'qotmang.
ax = oylik.plot(marker="o", figsize=(9, 3.6), title="Oylik tushum, mln so'm") ax.set_xticks(range(1, 13)) ax.legend(title="filial", ncol=5) plt.show()

Hamma filialda yanvar va fevral — yilning eng past oylari, keyin mart keskin ko'tariladi. Bu — mavsumiylik. Lekin cho'qqi hamma joyda bir xil emas: 1- va 4-filialda dekabr, 2-filialda mart, 3-filialda esa iyun eng yaxshi oy. Rasmsiz bu naqshlar 12 × 5 sonli jadvalda ko'rinmasdi, umumiy yig'indida esa filiallar farqi umuman yo'qolardi.
filter: guruhlarni saralash
kuchli_kunlar = savdo.groupby("sana").filter(lambda g: g["tushum"].sum() > 1_500_000) print("kunlar:", savdo["sana"].nunique(), "->", kuchli_kunlar["sana"].nunique()) print("bu kunlarning eng ko'p uchragan hafta kuni:", kuchli_kunlar["sana"].dt.day_name().value_counts().idxmax())
kunlar: 365 -> 171 bu kunlarning eng ko'p uchragan hafta kuni: Sunday
filter — butun guruhni shart bilan qoldiradi yoki tashlaydi: bu yerda faqat jami tushumi 1.5 mln dan oshgan kunlarning barcha qatorlari qoldi. Ular orasida eng ko'p uchragan kun — dam olish kuni: do'konlarga odam shanba-yakshanba ko'proq keladi.
Xulosa
groupby("kalit")["ustun"].funksiya()— bo'lish → hisoblash → birlashtirish; guruh nomlari index ga aylanadi.agg(nom=("ustun", "funksiya"))— bir nechta hisob, aniq nomlar bilan.size— qatorlar,nunique— noyob qiymatlar,count— bo'sh bo'lmaganlar.- Ikki bosqichli guruhlash — "o'rtacha chek" kabi savollarda: avval ichki birlikni (chek) yig'ing.
- Ikki kalit +
unstack→ o'qiladigan jadval;pivot_table— buning bitta buyrug'i. transform— natija har qatorga;filter— butun guruhni saralash;crosstab— sanash va foiz.
Mashqlar
- Har mahsulot (
mahsulot_id) bo'yicha jami sotilgan dona va tushumni toping. Eng ko'p tushum keltirgani qaysi? - Har filialda o'rtacha chekda nechta turdagi mahsulot bor?
- Hafta kunlari bo'yicha o'rtacha kunlik tushum (maslahat: avval kun bo'yicha yig'ing, keyin hafta kuni bo'yicha o'rtacha).
Javoblar
savdo.groupby("mahsulot_id").agg(dona=("miqdor", "sum"), tushum=("tushum", "sum")).sort_values("tushum")— oxirgi qator.savdo.groupby(["filial_id", "chek_id"]).size().groupby("filial_id").mean().kunlik = savdo.groupby("sana")["tushum"].sum(), keyinkunlik.groupby(kunlik.index.day_name()).mean().
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.