Asosiy qismga o'tish

merge va concat: jadvallarni birlashtirish

15-bob 10 kod bloki 1466 so'z

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

Sahna: ma'lumot bir nechta faylda

Savdo faylida mahsulot raqami bor, nomi yo'q. Filial raqami bor, nomi yo'q. Mahsulot tannarxi — boshqa faylda. Bu tasodif emas: ma'lumotlar bazasida ma'lumot ataylab bo'linadi — har mahsulotning nomini million chekda takrorlamaslik uchun. Tahlil uchun esa jadvallarni qayta birlashtirish kerak. Bu bob — merge, va u yashiradigan ikkita qopqon.

python8 qator
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"]
mahsulotlar = pd.read_csv(DATA / "mahsulotlar.csv")
filiallar = pd.read_csv(DATA / "filiallar.csv")
print(savdo.shape, mahsulotlar.shape, filiallar.shape)
filiallar
Chiqish
(11352, 9) (11, 4) (4, 4)
filial_idnomtumanochilgan
01ChilonzorChilonzor2019-03-01
12YunusobodYunusobod2020-07-15
23SergeliSergeli2022-01-10
34OlmazorOlmazor2023-05-20

Birinchi merge va birinchi qopqon

Har qatorga mahsulot nomi va kategoriyasini qo'shamiz:

python3 qator
birga = savdo.merge(mahsulotlar, on="mahsulot_id")
print("qatorlar:", len(savdo), "->", len(birga))
print("jami tushum:", savdo["tushum"].sum(), "->", birga["tushum"].sum())
Chiqish
qatorlar: 11352 -> 12536
jami tushum: 564276000 -> 637801000

To'xtang. Biz faqat ustun qo'shdik — qatorlar soni o'zgarmasligi kerak edi. Lekin qatorlar ko'paydi, va jami tushum ham oshib ketdi. Pul havodan paydo bo'lmaydi — demak xato. Sababini qidiramiz:

python2 qator
print(mahsulotlar["mahsulot_id"].is_unique)
mahsulotlar[mahsulotlar["mahsulot_id"].duplicated(keep=False)]
Chiqish
False
mahsulot_idnomkategoriyatannarx
56ChoyIchimliklar18000
66Choy (ko'k)Ichimliklar17000

Katalogda 6-mahsulot ikki marta yozilgan: "Choy" va "Choy (ko'k)". merge har bir choy sotuvini ikkala yozuv bilan juftlab, qatorni ikkiga ko'paytirdi. Bunday xato Excel dagi VLOOKUP da bo'lmaydi (u birinchisini oladi) — shuning uchun pandas ga o'tganlar uni kutmaydi.

Himoya: validate

python4 qator
try:
    savdo.merge(mahsulotlar, on="mahsulot_id", validate="many_to_one")
except pd.errors.MergeError as xato:
    print("MergeError:", xato)
Chiqish
MergeError: Merge keys are not unique in right dataset; not a many-to-one merge

validate="many_to_one" — pandas ga kutganimizni aytamiz: chap tomonda bitta mahsulot ko'p marta uchrashi mumkin (ko'p chek), o'ng tomonda esa bir marta. Kutilgan bo'lmasa — jim ko'payish o'rniga darhol xato. Har bir "ma'lumotnoma" jadvali bilan merge da validate yozing.

Katalogni tuzatamiz. Qaysi yozuv to'g'ri — bu biznes savoli (do'kondan so'rash kerak); biz eski yozuvni, ya'ni birinchisini qoldiramiz va qarorimizni yozib qo'yamiz:

python3 qator
katalog = mahsulotlar.drop_duplicates("mahsulot_id", keep="first")
birga = savdo.merge(katalog, on="mahsulot_id", validate="many_to_one")
print("qatorlar:", len(birga), "| tushum o'zgarmadimi:", birga["tushum"].sum() == savdo["tushum"].sum())
Chiqish
qatorlar: 11352 | tushum o'zgarmadimi: True

Endi qatorlar soni ham, jami tushum ham asl bilan bir xil. Har merge dan keyin shu ikki sonni tekshiring.

Ikkinchi qopqon: yo'qolgan qatorlar

Endi filial nomlari:

merge turlari: inner, left, right, outer — qaysi qatorlar qoladi

merge turlari: inner, left, right, outer — qaysi qatorlar qoladi

python3 qator
ichki = birga.merge(filiallar, on="filial_id", how="inner", suffixes=("", "_filial"))
print("inner bilan qatorlar:", len(birga), "->", len(ichki))
print("yo'qolgan tushum:", birga["tushum"].sum() - ichki["tushum"].sum())
Chiqish
inner bilan qatorlar: 11352 -> 10618
yo'qolgan tushum: 35842000

Standart how="inner" — faqat ikkala jadvalda bor kalitlar qoladi. Qatorlar kamaydi, tushumning bir qismi yo'qoldi — xato bermasdan. Qaysilar?

python3 qator
chap = birga.merge(filiallar, on="filial_id", how="left", suffixes=("", "_filial"), indicator=True)
print(chap["_merge"].value_counts().to_dict())
print("ro'yxatda yo'q filiallar:", chap.loc[chap["_merge"] == "left_only", "filial_id"].unique())
Chiqish
{'both': 10618, 'left_only': 734, 'right_only': 0}
ro'yxatda yo'q filiallar: [5]

how="left" — chap jadvaldagi hamma qator qoladi; o'ngda jufti yo'qlarga NaN. indicator=True — _merge ustuni har qator qayerdan kelganini aytadi: both (ikkalasida), left_only (faqat chapda). 5-filial savdo faylida bor, filiallar ro'yxatida — yo'q. 14-bobdagi "5-filial juda kam topgan" sirining javobi: u oktyabrda ochilgan va ro'yxatga hali qo'shilmagan.

Qaysi how ni tanlash — savolga bog'liq:

how Qoladi Qachon
inner ikkalasida bor faqat to'liq ma'lumotli qatorlar kerak
left chapdagi hammasi asosiy jadval chapda, unga ma'lumot qo'shamiz (eng ko'p)
right o'ngdagi hammasi left ning teskarisi
outer hammasi ikki ro'yxatni solishtirish: nima qayerda yo'q

Biz left ni tanlaymiz va yo'q nomni aniq belgilaymiz:

python2 qator
toliq = chap.drop(columns="_merge").assign(nom_filial=lambda d: d["nom_filial"].fillna("Yangi (ro'yxatda yo'q)"))
toliq.groupby("nom_filial")["tushum"].sum().div(1e6).round(1).sort_values()
nom_filialtushum
Yangi (ro'yxatda yo'q)35.8
Sergeli127.3
Olmazor128.4
Yunusobod133.3
Chilonzor139.5

Natija: foyda kategoriya bo'yicha

Endi tannarx ham bor — foydani hisoblash mumkin. Bu savolga bitta jadval javob bera olmasdi:

python11 qator
toliq["foyda"] = (toliq["narx"] - toliq["tannarx"]) * toliq["miqdor"]
kat = toliq.groupby("kategoriya")[["tushum", "foyda"]].sum().div(1e6)
kat["marja_%"] = (kat["foyda"] / kat["tushum"] * 100).round(1)
kat = kat.sort_values("foyda")

fig, (chap_ax, ong_ax) = plt.subplots(1, 2, figsize=(11, 3.4), sharey=True)
kat[["tushum", "foyda"]].plot(kind="barh", ax=chap_ax, color=["#a8c7fa", "#137333"], title="Tushum va foyda, mln so'm")
chap_ax.legend(loc="center right")
kat["marja_%"].plot(kind="barh", ax=ong_ax, color="#b06000", title="Foyda marjasi, %")
plt.show()
kat.round(1)
kategoriyatushumfoydamarja_%
Non mahsulotlari14.34.330
Ichimliklar85.124.929.3
Bakaleya229.553.123.1
Sut mahsulotlari235.464.527.4

Uchta jadval birlashdi va yangi savol ochildi: qaysi kategoriya ko'p pul keltiradi, qaysi biri esa har so'mdan ko'p foyda. Bular har doim bir xil emas — marja chizmasini tushum chizmasi bilan solishtiring.

concat: ustma-ust qo'yish

merge — kalit bo'yicha yoniga qo'shadi. Bir xil tuzilishdagi jadvallarni ostiga qo'shish esa concat:

python6 qator
yanvar = savdo[savdo["sana"].dt.month == 1]
fevral = savdo[savdo["sana"].dt.month == 2]
ikki_oy = pd.concat([yanvar, fevral], ignore_index=True)
print(len(yanvar), "+", len(fevral), "=", len(ikki_oy))
belgili = pd.concat([yanvar, fevral], keys=["yanvar", "fevral"], names=["oy", None])
belgili.groupby(level="oy")["tushum"].sum()
Chiqish
636 + 564 = 1200
oytushum
fevral27149000
yanvar29338000

Har oy alohida faylda kelganda (eksportlarda tez-tez) — concat. ignore_index=True — yangi 0, 1, 2... index (aks holda takror index lar, 6-bob mashqidagi kabi). keys= — har qism qaysi fayldan kelganini index ga yozib qo'yadi.

Xulosa

  • merge(on="kalit", how=...) — kalit bo'yicha yoniga qo'shish; concat — ostiga.
  • Ma'lumotnomada takror kalit → qatorlar va summalar jimgina ko'payadi. Himoya: validate="many_to_one".
  • how="inner" (standart) jufti yo'q qatorlarni jimgina tashlaydi. Odatda left + indicator=True.
  • Har merge dan keyin: qatorlar soni va asosiy summa o'zgarmadimi?
  • Takror kalit yoki yo'q yozuvni tuzatish — biznes qarori; uni kodda aniq yozing.

Mashqlar

  1. outer merge bilan savdo va filiallar ro'yxatini solishtiring: ro'yxatda bor, lekin savdosi yo'q filial bormi?
  2. Har filial va kategoriya bo'yicha foydani pivot_table bilan jadval qiling.
  3. Nega katalog ni keep="first" bilan emas, keep="last" bilan tuzatsak, jami foyda o'zgaradi, tushum esa yo'q?

Javoblar

  1. savdo.merge(filiallar, on="filial_id", how="outer", indicator=True)["_merge"].value_counts() — right_only 0: hamma ro'yxatdagi filialda savdo bor.
  2. toliq.pivot_table(index="nom_filial", columns="kategoriya", values="foyda", aggfunc="sum").
  3. Tushum savdo faylidagi narxdan hisoblanadi — katalogga bog'liq emas. Foyda esa tannarxga bog'liq, ikki choy yozuvining tannarxi har xil (18 000 va 17 000).

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar