Asosiy qismga o'tish

groupby: guruhlab hisoblash

14-bob 11 kod bloki 1435 so'z

Bu bobdagi kod shu fayllar bilan ishlaydio'z kompyuteringizda ishga tushiring

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.

python7 qator
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()
Chiqish
(11352, 9)
chek_idsanavaqtfilial_idmahsulot_idmiqdornarxtolovtushum
05000012025-01-01 00:00:0010:251914000Click4000
15000022025-01-01 00:00:0013:3714418000naqd72000
25000022025-01-01 00:00:0013:371145000naqd20000
35000022025-01-01 00:00:0013:3712112000naqd12000
45000032025-01-01 00:00:0011:05110162000karta62000

tushum — har qatorning puli: dona × narx.

Bo'lish, hisoblash, birlashtirish

groupby: qatorlar guruhlarga bo'linadi, har guruh bitta songa yig'iladi, natijalar birlashadi

groupby: qatorlar guruhlarga bo'linadi, har guruh bitta songa yig'iladi, natijalar birlashadi

python1 qator
savdo.groupby("filial_id")["tushum"].sum()
filial_idtushum
1139529000
2133251000
3127296000
4128358000
535842000

Uch qadam, bitta qator:

  1. Bo'lish (split): qatorlar filial_id qiymati bo'yicha guruhlarga ajratildi.
  2. Hisoblash (apply): har guruhning tushum ustuniga sum qo'llandi.
  3. 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

python7 qator
hisobot = savdo.groupby("filial_id").agg(
    qatorlar=("chek_id", "size"),
    cheklar=("chek_id", "nunique"),
    tushum=("tushum", "sum"),
    ortacha_qator=("tushum", "mean"),
)
hisobot
filial_idqatorlarcheklartushumortacha_qator
12754136813952900050664.125
22658133013325100050132.054
32597131812729600049016.558
42609130912835800049198.16
57343623584200048831.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.

python4 qator
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())
Chiqish
           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

python4 qator
tolov_filial = savdo.groupby(["filial_id", "tolov"])["tushum"].sum().div(1e6).round(1)
print(tolov_filial.head(4))
jadval = tolov_filial.unstack("tolov")
jadval
Chiqish
filial_id  tolov
1          Click    31.5
           Payme    19.0
           karta    41.4
           naqd     47.6
Name: tushum, dtype: float64
filial_idClickPaymekartanaqd
131.51941.447.6
228.221.240.343.6
324.617.842.442.5
429.418.737.342.9
56.85.211.712.2

Ikki kalit — ikki darajali index. unstack("tolov") ichki darajani ustunlarga "yoyadi": endi o'qilishi oson jadval — qatorlar filiallar, ustunlar to'lov turlari.

python3 qator
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:

python3 qator
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_idmahsulot_idtushumchek_jamichekdagi_ulush
15000024720001040000.69
25000021200001040000.19
35000022120001040000.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

python2 qator
ulush = pd.crosstab(savdo["tolov"], savdo["filial_id"], normalize="columns").mul(100).round(1)
ulush
tolov12345
Click2221.420.421.418.9
Payme14.716.714.414.815.9
karta29.329.832.328.630.7
naqd3432.132.835.234.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"

python3 qator
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)
oy12345
911.21010.813.9NaN
1013.612.81210.110.8
1110.111.39.610.810.3
1216.31213.915.114.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.

python4 qator
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

python3 qator
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())
Chiqish
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

  1. Har mahsulot (mahsulot_id) bo'yicha jami sotilgan dona va tushumni toping. Eng ko'p tushum keltirgani qaysi?
  2. Har filialda o'rtacha chekda nechta turdagi mahsulot bor?
  3. Hafta kunlari bo'yicha o'rtacha kunlik tushum (maslahat: avval kun bo'yicha yig'ing, keyin hafta kuni bo'yicha o'rtacha).

Javoblar

  1. savdo.groupby("mahsulot_id").agg(dona=("miqdor", "sum"), tushum=("tushum", "sum")).sort_values("tushum") — oxirgi qator.
  2. savdo.groupby(["filial_id", "chek_id"]).size().groupby("filial_id").mean().
  3. kunlik = savdo.groupby("sana")["tushum"].sum(), keyin kunlik.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.

Telegramda yozish Narxlar