Asosiy qismga o'tish

Dataset qurish: tozalash, label va split

38-bob 18 kod bloki 4031 so'z

Sahna: 300 qator, biror foydali narsa yo'q

36-bob ish/xom/elonlar_xom.csv ni qoldirdi. Unda 300 qator bor, lekin hech bir ustun modelga berib bo'ladigan holatda emas: narx uch xil formatda matn, maydon "45.5 m²" ko'rinishida, dublikatlar o'chirilmagan.

Bu bob xom fayldan dataset yasaydi. Dataset — shunchaki toza jadval emas. Dataset — bu:

  1. har ustun tipi va diapazoni ma'lum
  2. har qator nimani anglatishi yozilgan
  3. target aniq belgilangan
  4. train/val/test to'g'ri ajratilgan
  5. hammasi takrorlanadigan
python21 qator
import re
import sys
import numpy as np
import pandas as pd

# 36-bobda yozgan yig'uvchimizni qayta ishlatamiz — xom ma'lumot shu yerdan keladi.
# Har bob mustaqil ishlashi kerak, shuning uchun faylga emas, MANBAGA murojaat qilamiz.
sys.path.insert(0, str(ISH))
from yiguv.tahlil import sahifani_tahlil

FIX = DATA / "fixture"
yozuvlar = []
for sahifa in sorted(FIX.glob("elonlar_*.html")):
    yozuvlar += sahifani_tahlil(sahifa.read_text(encoding="utf-8"))
xom = pd.DataFrame(yozuvlar)

print(f"Xom ma'lumot: {xom.shape[0]} qator, {xom.shape[1]} ustun")
print()
print(xom.dtypes.to_string())
print()
print("Hamma ustun `object` — ya'ni MATN. Bitta ham son yo'q.")
Chiqish
Xom ma'lumot: 300 qator, 7 ustun

manba_id      object
sarlavha      object
narx_xom      object
xona_xom      object
maydon_xom    object
tuman         object
qavat_xom     object

Hamma ustun `object` — ya'ni MATN. Bitta ham son yo'q.

Qoida: har qadamda qator sanaladi

Jim yo'qolgan qatorlar — eng xavfli xato turi

Tozalash jarayonida dropna(), drop_duplicates(), filtrlar ketma-ket qo'llanadi. Har biri qatorlarni o'chiradi.

Men ko'rgan eng ko'p uchraydigan xato: talaba 10 000 qatorli fayldan boshlaydi, 6 qadam tozalash qiladi, oxirida 400 qator qoladi va buni sezmaydi. Keyin "modelim nega yomon?" deb so'raydi.

Yechim — qadam jurnali. Har amaldan keyin qator soni yoziladi va yo'qolgan qatorlar sababi bilan hisobga olinadi.

Agar bir qadamda 50% qator yo'qolsa, bu sizdan qaror talab qiladi: shunchaki tashlab yuborasizmi, yoki to'ldirasizmi? Jurnal bo'lmasa, siz bu savolni ko'rmaysiz ham.

python15 qator
class Jurnal:
    """Har tozalash qadamini yozib boradi."""
    def __init__(self, boshlangich):
        self.qadamlar = [{"qadam": "boshlanish", "qator": boshlangich, "yo'qoldi": 0}]
    def yoz(self, nom, qator):
        oldingi = self.qadamlar[-1]["qator"]
        self.qadamlar.append({"qadam": nom, "qator": qator, "yo'qoldi": oldingi - qator})
        return qator
    def jadval(self):
        t = pd.DataFrame(self.qadamlar)
        t["qolgan %"] = (t["qator"] / t["qator"].iloc[0] * 100).round(1)
        return t

jurnal = Jurnal(len(xom))
print(f"Jurnal boshlandi: {len(xom)} qator")
Chiqish
Jurnal boshlandi: 300 qator

Narxni songa aylantirish

Eng qiyin ustun. Uch format, uchta qoida.

python3 qator
print("Xom narx qiymatlari (birinchi 10 noyob):")
for v in xom["narx_xom"].dropna().unique()[:10]:
    print(f"  {v!r}")
Chiqish
Xom narx qiymatlari (birinchi 10 noyob):
  "10 625 000 so'm"
  "12 500 000 so'm"
  '500\xa0у.е.'
  'Kelishilgan'
  '450\xa0у.е.'
  "8 750 000 so'm"
  '700\xa0у.е.'
  '400\xa0у.е.'
  '350\xa0у.е.'
  '850\xa0у.е.'

shu faylni yaratingtozalash/matndan_son.py

python33 qator
"""Matn ko'rinishidagi qiymatlarni songa aylantirish."""
import re

import numpy as np

SOM_KURSI = 12500          # 1 USD = 12500 so'm (dataset yasalgan paytdagi kurs)


def narxni_ol(matn, kurs=SOM_KURSI):
    """Narx matnini USD ga aylantiradi.

    Uch format qo'llab-quvvatlanadi:
      "500 у.е."        -> 500.0
      "6 250 000 so'm"  -> 500.0
      "Kelishilgan"     -> nan   (raqam YO'Q, to'qib chiqarilmaydi)
    """
    if not isinstance(matn, str):
        return np.nan
    if "Kelishilgan" in matn:
        return np.nan                      # narx yo'q — taxmin qilmaymiz
    raqamlar = re.sub(r"[^\d]", "", matn.replace("\xa0", " "))
    if not raqamlar:
        return np.nan
    qiymat = int(raqamlar)
    return qiymat / kurs if "so'm" in matn else float(qiymat)


def birinchi_son(matn, naqsh=r"([\d.]+)"):
    """Matndan birinchi sonni ajratadi: "45.5 m²" -> 45.5, "11-qavat" -> 11.0"""
    if not isinstance(matn, str):
        return np.nan
    topildi = re.search(naqsh, matn)
    return float(topildi.group(1)) if topildi else np.nan
python13 qator
from tozalash.matndan_son import narxni_ol, birinchi_son

sinovlar = ["500\xa0у.е.", "6 250 000 so'm", "Kelishilgan", None, "12 500 000 so'm"]
print(f"{'kirish':<22} {'natija (USD)':>14}")
print("-" * 38)
for s in sinovlar:
    print(f"{repr(s):<22} {narxni_ol(s)!s:>14}")
print()
RAQAM = r"(\d+)"
maydon_sinov = birinchi_son("45.5 m²")
qavat_sinov = birinchi_son("11-qavat", RAQAM)
print(f"birinchi_son('45.5 m²')  = {maydon_sinov}")
print(f"birinchi_son('11-qavat') = {qavat_sinov}")
Chiqish
kirish                   natija (USD)
--------------------------------------
'500\xa0у.е.'                   500.0
"6 250 000 so'm"                500.0
'Kelishilgan'                     nan
None                              nan
"12 500 000 so'm"              1000.0

birinchi_son('45.5 m²')  = 45.5
birinchi_son('11-qavat') = 11.0

Yo'q qiymatni to'qib chiqarmaslik

"Kelishilgan" ni ko'rganda o'rtacha narx qo'yish juda jozibali — qator saqlanadi, NaN yo'qoladi.

Qilmang. Siz bu uyning narxini bilmaysiz. O'rtacha qo'ysangiz, modelga "bu uy o'rtacha narxda" degan yolg'on ma'lumot berasiz. 4-bobda imputatsiyani ko'rganmiz, lekin target ni imputatsiya qilish boshqa narsa: target — bu modelning haqiqat manbasi. Uni to'qib chiqarish butun o'qitishni buzadi.

Qoida: feature ni to'ldirish mumkin, target ni — yo'q. Target yo'q bo'lsa, qator o'qitishga yaramaydi.

python12 qator
toza = pd.DataFrame({
    "manba_id": xom["manba_id"],
    "tuman": xom["tuman"],
    "xonalar": xom["xona_xom"].apply(lambda s: birinchi_son(s, r"(\d+)")),
    "maydon_m2": xom["maydon_xom"].apply(birinchi_son),
    "qavat": xom["qavat_xom"].apply(lambda s: birinchi_son(s, r"(\d+)")),
    "narx_usd": xom["narx_xom"].apply(narxni_ol),
})
print("Aylantirishdan keyin bo'sh qiymatlar:")
for u in ["tuman", "xonalar", "maydon_m2", "qavat", "narx_usd"]:
    n = int(toza[u].isna().sum())
    print(f"  {u:<12} {n:>4} ta bo'sh  ({n / len(toza):.1%})")
Chiqish
Aylantirishdan keyin bo'sh qiymatlar:
  tuman           0 ta bo'sh  (0.0%)
  xonalar        26 ta bo'sh  (8.7%)
  maydon_m2      35 ta bo'sh  (11.7%)
  qavat           0 ta bo'sh  (0.0%)
  narx_usd       46 ta bo'sh  (15.3%)

Target yo'q bo'lgan qatorlarni ajratish

python8 qator
narxsiz = int(toza["narx_usd"].isna().sum())
toza_t = toza[toza["narx_usd"].notna()].copy()
jurnal.yoz("narxi yo'q qatorlar olib tashlandi", len(toza_t))
print(f"Narxi yo'q ('Kelishilgan' va bo'sh): {narxsiz} qator")
print(f"Qoldi: {len(toza_t)} qator")
print()
print("Bu qatorlar BEKOR emas — ular bashorat qilish uchun ishlatiladi.")
print("Faqat O'QITISH uchun yaramaydi. Shuning uchun ularni alohida saqlash mumkin.")
Chiqish
Narxi yo'q ('Kelishilgan' va bo'sh): 46 qator
Qoldi: 254 qator

Bu qatorlar BEKOR emas — ular bashorat qilish uchun ishlatiladi.
Faqat O'QITISH uchun yaramaydi. Shuning uchun ularni alohida saqlash mumkin.
python5 qator
oldin = len(toza_t)
toza_t = toza_t.dropna(subset=["xonalar", "maydon_m2", "qavat"])
jurnal.yoz("feature lari to'liq bo'lmagan qatorlar", len(toza_t))
print(f"Feature si yetishmaydigan qatorlar: {oldin - len(toza_t)}")
print(f"Qoldi: {len(toza_t)} qator")
Chiqish
Feature si yetishmaydigan qatorlar: 47
Qoldi: 207 qator

Tekshiruv: ma'lumot shartnomasi

Tozalangan ma'lumot kutilgan diapazonda ekanini tekshirish kerak. Aks holda xato keyinroq, modelni o'qitganda chiqadi.

shu faylni yaratingtozalash/shartnoma.py

python33 qator
"""Dataset shartnomasi: har ustun uchun tip va diapazon."""

SHARTNOMA = {
    "tuman":     {"tur": "matn", "ruxsat": {"Yunusobod", "Chilonzor", "Mirzo Ulug'bek",
                                            "Shayxontohur", "Yakkasaroy", "Olmazor",
                                            "Sergeli", "Bektemir"}},
    "xonalar":   {"tur": "son", "min": 1, "maks": 10},
    "maydon_m2": {"tur": "son", "min": 15, "maks": 400},
    "qavat":     {"tur": "son", "min": 1, "maks": 50},
    "narx_usd":  {"tur": "son", "min": 50, "maks": 20000},
}


def tekshir(df, shartnoma=SHARTNOMA):
    """Shartnomaga mos kelmagan holatlar ro'yxatini qaytaradi. Bo'sh ro'yxat — hammasi joyida."""
    muammolar = []
    for ustun, qoida in shartnoma.items():
        if ustun not in df.columns:
            muammolar.append(f"{ustun}: ustun YO'Q")
            continue
        qiymat = df[ustun]
        if qoida["tur"] == "son":
            chegaradan = ((qiymat < qoida["min"]) | (qiymat > qoida["maks"])).sum()
            if chegaradan:
                muammolar.append(
                    f"{ustun}: {chegaradan} qiymat [{qoida['min']}, {qoida['maks']}] dan tashqarida")
        else:
            notogri = set(qiymat.dropna().unique()) - qoida["ruxsat"]
            if notogri:
                muammolar.append(f"{ustun}: ruxsat etilmagan qiymat {sorted(notogri)[:5]}")
        if qiymat.isna().any():
            muammolar.append(f"{ustun}: {int(qiymat.isna().sum())} bo'sh qiymat")
    return muammolar
python11 qator
from tozalash.shartnoma import tekshir

muammolar = tekshir(toza_t)
print(f"Shartnoma tekshiruvi: {len(muammolar)} muammo")
for m in muammolar:
    print(f"  - {m}")
if not muammolar:
    print("  (hammasi shartnomaga mos)")
print()
print("Shartnoma — kodda yozilgan KUTISH. U buzilsa, siz darhol bilasiz,")
print("3 kundan keyin 'modelim g'alati' deb o'ylamasdan.")
Chiqish
Shartnoma tekshiruvi: 0 muammo
  (hammasi shartnomaga mos)

Shartnoma — kodda yozilgan KUTISH. U buzilsa, siz darhol bilasiz,
3 kundan keyin 'modelim g'alati' deb o'ylamasdan.

Dublikat: guruh identifikatori

36-bobda o'lchagandik: manba_id noyob bo'lsa ham, bitta uy bir necha marta e'lon qilingan. Endi har uyga guruh raqami beramiz.

python9 qator
toza_t["guruh"] = toza_t.groupby(["tuman", "maydon_m2", "xonalar"]).ngroup()
noyob_uy = toza_t["guruh"].nunique()
print(f"Qator soni      : {len(toza_t)}")
print(f"Noyob uy (guruh): {noyob_uy}")
print(f"Ortiqcha yozuv  : {len(toza_t) - noyob_uy}  ({(len(toza_t) - noyob_uy) / len(toza_t):.1%})")
print()
katta = toza_t["guruh"].value_counts()
print(f"Eng ko'p takrorlangan uy {int(katta.iloc[0])} marta e'lon qilingan:")
show(toza_t[toza_t["guruh"] == katta.index[0]][["manba_id", "tuman", "maydon_m2", "xonalar", "narx_usd"]])
Chiqish
Qator soni      : 207
Noyob uy (guruh): 176
Ortiqcha yozuv  : 31  (15.0%)

Eng ko'p takrorlangan uy 5 marta e'lon qilingan:
manba_idtumanmaydon_m2xonalarnarx_usd
131Mirzo Ulug'bek60.42600
176Mirzo Ulug'bek60.42600
190Mirzo Ulug'bek60.42600
250Mirzo Ulug'bek60.42600
284Mirzo Ulug'bek60.42600

Dublikatni O'CHIRISH shart emas — ajratishda hisobga olish shart

Birinchi fikr: dublikatni drop_duplicates() bilan o'chirish. Ba'zan bu to'g'ri.

Lekin takroriy e'lon ham ma'lumot: uy uzoq vaqt ijaraga berilmaganini ko'rsatadi. O'chirsangiz, shu signalni yo'qotasiz.

Muhimi — bitta uy train va test ga ikkalasiga tushmasligi. Buning yo'li: guruh ustunini saqlash va split ni guruh bo'yicha qilish. Pastdagi bo'limda nima bo'lishini o'lchaymiz.

Split: endi o'lchaymiz, nega guruh muhim

python26 qator
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split, GroupShuffleSplit
from sklearn.metrics import r2_score

X = pd.get_dummies(toza_t[["tuman", "xonalar", "maydon_m2", "qavat"]], columns=["tuman"])
y = toza_t["narx_usd"].values
guruhlar = toza_t["guruh"].values

natija = []
for nom, yasa in [("KNN (k=1)", lambda: KNeighborsRegressor(1)),
                  ("KNN (k=3)", lambda: KNeighborsRegressor(3)),
                  ("random forest", lambda: RandomForestRegressor(200, random_state=0))]:
    tasodifiy = [r2_score(yb, yasa().fit(Xa, ya).predict(Xb))
                 for Xa, Xb, ya, yb in (train_test_split(X, y, test_size=.25, random_state=s)
                                        for s in range(5))]
    guruhli = []
    for s in range(5):
        tr, te = next(GroupShuffleSplit(n_splits=1, test_size=.25,
                                        random_state=s).split(X, y, groups=guruhlar))
        guruhli.append(r2_score(y[te], yasa().fit(X.iloc[tr], y[tr]).predict(X.iloc[te])))
    natija.append({"model": nom,
                   "tasodifiy split R2": round(float(np.mean(tasodifiy)), 3),
                   "guruh split R2": round(float(np.mean(guruhli)), 3),
                   "soxta farq": round(float(np.mean(tasodifiy) - np.mean(guruhli)), 3)})
show(pd.DataFrame(natija))
modeltasodifiy split R2guruh split R2soxta farq
KNN (k=1)-0.796-0.970.174
KNN (k=3)-0.28-0.3780.098
random forest-0.126-0.2970.171

Uchta model, uchta xil ichki mexanizm — lekin farq ishorasi bir xil: tasodifiy split har safar yaxshiroq ko'rsatadi.

Bu datasetda R2 manfiy — va bu TO'G'RI natija

Jadvaldagi R2 qiymatlari manfiy. Bu xato emas, va buni tushunish muhim.

datasets/fixture_qur.py generatorida narx tasodifiy tanlanadi — u tuman, maydon yoki xonaga bog'liq emas. Ya'ni bu ma'lumotda o'rganiladigan naqsh yo'q.

Manfiy R2 ma'nosi: model o'rtacha qiymatni aytishdan ham yomonroq ishlaydi. 6-bobdagi baza aynan shu — DummyRegressor o'rtachani aytadi va R2 = 0 oladi. Modelimiz 0 dan past, demak u shovqinga moslashgan (overfitting).

Nega bu bizga qulay: naqsh yo'q bo'lgani uchun har qanday ijobiy natija faqat leakage dan kelishi mumkin. Shuning uchun "tasodifiy split" ustunining yuqoriligi — sof o'lchangan leakage, boshqa hech narsa emas.

Haqiqiy loyihada siz buni ko'rmaysiz: o'sha yerda naqsh ham bor, leakage ham bor, va ikkisi aralashib ketadi. Shuning uchun halol split birinchi navbatda qilinadi, natijani ko'rgandan keyin emas.

Uch qismga ajratish

python22 qator
# 1-bosqich: test ni GURUH bo'yicha ajratamiz
tr_idx, te_idx = next(GroupShuffleSplit(n_splits=1, test_size=0.2,
                                        random_state=42).split(X, y, groups=guruhlar))
qolgan = toza_t.iloc[tr_idx]
test = toza_t.iloc[te_idx]

# 2-bosqich: qolganidan validation ni ham GURUH bo'yicha ajratamiz
X2 = X.iloc[tr_idx]
tr2, va2 = next(GroupShuffleSplit(n_splits=1, test_size=0.2,
                                  random_state=42).split(X2, y[tr_idx],
                                                         groups=qolgan["guruh"].values))
train = qolgan.iloc[tr2]
val = qolgan.iloc[va2]

print(f"{'bo`lak':<8} {'qator':>7} {'noyob uy':>10} {'ulush':>8}")
print("-" * 36)
for nom, b in [("train", train), ("val", val), ("test", test)]:
    print(f"{nom:<8} {len(b):>7} {b['guruh'].nunique():>10} {len(b) / len(toza_t):>7.1%}")
print()
kesishma = (set(train["guruh"]) & set(test["guruh"])) | (set(train["guruh"]) & set(val["guruh"]))
print(f"Bo'laklar orasida umumiy uy: {len(kesishma)}   <- 0 bo'lishi SHART")
jurnal.yoz("uch bo'lakka ajratildi", len(train) + len(val) + len(test))
Chiqish
bo`lak     qator   noyob uy    ulush
------------------------------------
train        136        112   65.7%
val           33         28   15.9%
test          38         36   18.4%

Bo'laklar orasida umumiy uy: 0   <- 0 bo'lishi SHART

Qadam jurnali: hamma qator hisobda

python4 qator
show(jurnal.jadval())
print(f"Boshlangan: {jurnal.qadamlar[0]['qator']} qator")
print(f"Qolgan    : {jurnal.qadamlar[-1]['qator']} qator")
print(f"Yo'qolgan : {jurnal.qadamlar[0]['qator'] - jurnal.qadamlar[-1]['qator']} qator — har biri sababi bilan yuqorida")
Chiqish
Boshlangan: 300 qator
Qolgan    : 207 qator
Yo'qolgan : 93 qator — har biri sababi bilan yuqorida
qadamqatoryo'qoldiqolgan %
boshlanish3000100
narxi yo'q qatorlar olib tashlandi2544684.7
feature lari to'liq bo'lmagan qatorlar2074769
uch bo'lakka ajratildi207069

Datasheet: datasetning pasporti

Hujjatsiz dataset — vaqt bombasi

Olti oydan keyin siz (yoki hamkasbingiz) bu faylni ochadi va so'raydi: narx qaysi valyutada? qachon yig'ilgan? nega 93 qator yo'q? Kelishilgan qatorlar qayerda?

Javoblar yozilmagan bo'lsa, dataset ishonchsiz bo'lib qoladi va qaytadan yasash kerak bo'ladi.

Shuning uchun har dataset bilan birga datasheet saqlanadi — oddiy matn fayl, 10 daqiqalik ish.

python42 qator
datasheet = f"""# uy_ijara dataseti — datasheet

## Nima
Toshkent ijara e'lonlari. Bitta qator = bitta e'lon.

## Manba
`datasets/fixture/elonlar_*.html` — SUN'IY saqlangan sahifalar
(`datasets/fixture_qur.py`, qat'iy seed). Jonli sayt EMAS.
Shuning uchun raqamlar har safar bir xil chiqadi.

## Hajmi
- xom yozuv: {len(xom)}
- tozalangandan keyin: {len(toza_t)}
- noyob uy: {toza_t['guruh'].nunique()}
- train / val / test: {len(train)} / {len(val)} / {len(test)}

## Target
`narx_usd` — oylik ijara narxi, AQSh dollarida.
Kurs: 1 USD = 12500 so'm (so'mda berilgan e'lonlar shu kurs bilan aylantirilgan).

## MUHIM ogohlantirish
Generatorda narx feature lardan MUSTAQIL tanlangan. Ya'ni bu datasetda
o'rganiladigan haqiqiy naqsh YO'Q. U faqat quyidagilarni o'rgatish uchun:
tozalash, dublikat, guruh bo'yicha split va leakage o'lchash.
Bu datasetda yaxshi R2 olishga urinish ma'nosiz.

## Olib tashlangan
- narxi yo'q qatorlar ("Kelishilgan"): o'qitishga yaramaydi, target to'qilmaydi
- feature si yetishmaydigan qatorlar

## Shaxsiy ma'lumot
Telefon raqamlari YIG'ILMAGAN (`yiguv/qoidalar.py` -> `shaxsiyni_tashla`).
Datasetda shaxsga doir hech qanday maydon yo'q.

## Split qoidasi
GroupShuffleSplit, guruh = (tuman, maydon_m2, xonalar).
Bitta uy faqat bitta bo'lakka tushadi. Tasodifiy split ISHLATILMAYDI.
"""
yol = ISH / "dataset"
yol.mkdir(exist_ok=True)
(yol / "DATASHEET.md").write_text(datasheet, encoding="utf-8")
print(datasheet)
Chiqish
# uy_ijara dataseti — datasheet

## Nima
Toshkent ijara e'lonlari. Bitta qator = bitta e'lon.

## Manba
`datasets/fixture/elonlar_*.html` — SUN'IY saqlangan sahifalar
(`datasets/fixture_qur.py`, qat'iy seed). Jonli sayt EMAS.
Shuning uchun raqamlar har safar bir xil chiqadi.

## Hajmi
- xom yozuv: 300
- tozalangandan keyin: 207
- noyob uy: 176
- train / val / test: 136 / 33 / 38

## Target
`narx_usd` — oylik ijara narxi, AQSh dollarida.
Kurs: 1 USD = 12500 so'm (so'mda berilgan e'lonlar shu kurs bilan aylantirilgan).

## MUHIM ogohlantirish
Generatorda narx feature lardan MUSTAQIL tanlangan. Ya'ni bu datasetda
o'rganiladigan haqiqiy naqsh YO'Q. U faqat quyidagilarni o'rgatish uchun:
tozalash, dublikat, guruh bo'yicha split va leakage o'lchash.
Bu datasetda yaxshi R2 olishga urinish ma'nosiz.

## Olib tashlangan
- narxi yo'q qatorlar ("Kelishilgan"): o'qitishga yaramaydi, target to'qilmaydi
- feature si yetishmaydigan qatorlar

## Shaxsiy ma'lumot
Telefon raqamlari YIG'ILMAGAN (`yiguv/qoidalar.py` -> `shaxsiyni_tashla`).
Datasetda shaxsga doir hech qanday maydon yo'q.

## Split qoidasi
GroupShuffleSplit, guruh = (tuman, maydon_m2, xonalar).
Bitta uy faqat bitta bo'lakka tushadi. Tasodifiy split ISHLATILMAYDI.
python10 qator
for nom, b in [("train", train), ("val", val), ("test", test)]:
    b.to_csv(yol / f"{nom}.csv", index=False)
narxsiz_df = toza[toza["narx_usd"].isna()]
narxsiz_df.to_csv(yol / "narxsiz_bashorat_uchun.csv", index=False)

print("ish/dataset/ papkasiga saqlandi:")
for p in sorted(yol.iterdir()):
    print(f"  {p.name:<32} {p.stat().st_size:>7} bayt")
print()
print("Endi bu papkani boshqa odamga berish mumkin: ma'lumot + hujjat + split qoidasi.")
Chiqish
ish/dataset/ papkasiga saqlandi:
  DATASHEET.md                        1234 bayt
  narxsiz_bashorat_uchun.csv          1359 bayt
  test.csv                            1484 bayt
  train.csv                           5153 bayt
  val.csv                             1278 bayt

Endi bu papkani boshqa odamga berish mumkin: ma'lumot + hujjat + split qoidasi.

Protokolga ulanish

Bu bob 0-bobdagi protokolning 1–4 qadamlarini bajardi, lekin o'z ma'lumotingiz ustida:

python7 qator
show(pd.DataFrame([
    {"Qadam": "1. Ustun tiplarini aniqla", "Bu bobda": "matn -> son, uch narx formati"},
    {"Qadam": "2. Bo'sh qiymatlarni hisobla", "Bu bobda": "jurnal bilan, har qadamda"},
    {"Qadam": "3. Target ni belgila", "Bu bobda": "narx_usd; target to'qilmaydi"},
    {"Qadam": "4. Split qil", "Bu bobda": "GroupShuffleSplit — leakage o'lchandi"},
    {"Qadam": "5. Baza qur", "Keyingi": "38-bob: fine-tuning; 6-bob: baza qoidasi"},
]))
QadamBu bobdaKeyingi
1. Ustun tiplarini aniqlamatn -> son, uch narx formatiNaN
2. Bo'sh qiymatlarni hisoblajurnal bilan, har qadamdaNaN
3. Target ni belgilanarx_usd; target to'qilmaydiNaN
4. Split qilGroupShuffleSplit — leakage o'lchandiNaN
5. Baza qurNaN38-bob: fine-tuning; 6-bob: baza qoidasi

Bugun nima o'rgandik

python10 qator
show(pd.DataFrame([
    {"Tushuncha": "Qadam jurnali", "Bitta jumla": "Har amaldan keyin qator sanaladi — jim yo'qotish bo'lmaydi"},
    {"Tushuncha": "Target to'qilmaydi", "Bitta jumla": "Feature to'ldiriladi, target — yo'q"},
    {"Tushuncha": "Ma'lumot shartnomasi", "Bitta jumla": "Tip va diapazon kodda yozilgan kutish"},
    {"Tushuncha": "Guruh identifikatori", "Bitta jumla": "Bitta uy = bitta guruh, barqaror maydonlardan"},
    {"Tushuncha": "GroupShuffleSplit", "Bitta jumla": "O'lchandi: tasodifiy split R2 ni soxta oshiradi"},
    {"Tushuncha": "Manfiy R2", "Bitta jumla": "O'rtachadan yomon — 6-bobdagi bazadan past"},
    {"Tushuncha": "Datasheet", "Bitta jumla": "Dataset pasporti — 10 daqiqa, keyin bir yil tejaydi"},
    {"Tushuncha": "Narxsiz qatorlar", "Bitta jumla": "O'qitishga yaramaydi, bashoratga yaraydi"},
]))
TushunchaBitta jumla
Qadam jurnaliHar amaldan keyin qator sanaladi — jim yo'qotish bo'lmaydi
Target to'qilmaydiFeature to'ldiriladi, target — yo'q
Ma'lumot shartnomasiTip va diapazon kodda yozilgan kutish
Guruh identifikatoriBitta uy = bitta guruh, barqaror maydonlardan
GroupShuffleSplitO'lchandi: tasodifiy split R2 ni soxta oshiradi
Manfiy R2O'rtachadan yomon — 6-bobdagi bazadan past
DatasheetDataset pasporti — 10 daqiqa, keyin bir yil tejaydi
Narxsiz qatorlarO'qitishga yaramaydi, bashoratga yaraydi

Keyingi bobda tayyor modelni o'z ma'lumotimizga moslashtiramiz: fine-tuning.

Bu bobni bepul o'qidingiz.

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

Telegramda yozish Narxlar