Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Mijoz segmentatsiyasi
- 2.2. Mavzu modellashtirish
- 2.3. Tavsiya tizimi asoslari
- 2.4. Siqish va kvantlash
- 2.5. Belgi muhandisligi
- 2.6. Qaysi vazifada qaysi mezon
- 2.7. Tuzoqlar
- 2.8. Mezon algoritmdan muhimroq
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Mijoz segmentatsiyasi: RFM va klasterlash
- Misol 2 — Mavzu modellashtirish
- Misol 3 — Tavsiya va siqish
- Misol 4 — Belgi muhandisligi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
16.11-dars: Qo'llanilishi
16-QISM — NAZORATSIZ O'RGANISH · 11-dars
1. Kirish va motivatsiya
Oldingi o'nta darsda algoritmlarni o'rgandik. Endi savol boshqacha: qaysi vazifada qaysi usul ishlaydi va natija nima berishi kerak?
Nazoratsiz o'rganishning amaliy qo'llanilishlari bir-biridan mezon bilan farq qiladi. Mijoz segmentatsiyasida muvaffaqiyat — marketing konversiyasi; mavzu modellashtirish — mavzularning tushunarliligi; siqishda — hajm va sifat muvozanati; tavsiya tizimida — bosish darajasi. Bir xil algoritm, butunlay boshqa baholash.
Bu darsda: mijoz segmentatsiyasi (RFM va xulq-atvor), mavzu modellashtirish (NMF va LDA), tavsiya tizimi asoslari (matritsani faktorlash), siqish (tasvir va vektor kvantlash) va belgi muhandisligi uchun nazoratsiz usullar.
Real vaziyat. Yangiliklar sayti 40 000 maqolani toifalarga ajratishi kerak edi. Qo'lda yorliqlash 3 oy va 12 mln so'm talab qilardi. NMF bilan 20 ta mavzu bir kunda ajratildi, muharrirlar ularga nom berdi va 94% maqola to'g'ri toifaga tushdi. Qolgan 6% qo'lda tuzatildi.
Bu darsda nazoratsiz o'rganishning qo'llanilishini o'rganamiz.
Bu darsda:
- Mijoz segmentatsiyasi
- Mavzu modellashtirish
- Tavsiya tizimi asoslari
- Siqish va kvantlash
- Belgi muhandisligi
- Qaysi vazifada qaysi mezon
- Tuzoqlar
- Amaliy: to'rt vazifa
ℹ Misollar real numpy/pandas/sklearn bilan (Python 3.14).
2. Nazariya — chuqur tushuntirish
2.1. Mijoz segmentatsiyasi
IKKI YONDASHUV:
1. RFM (Recency, Frequency, Monetary) - klassik, qoidaga asoslangan
R = oxirgi xariddan o'tgan kun
F = xaridlar soni
M = jami summa
Har birini 1-5 ballga bo'lib, 125 ta segment yoki guruhlash
2. XULQ-ATVOR klasterlashi - K-means/GMM bilan
RFM + toifalar + kanal + vaqt naqshlari
AMALIY QOIDALAR:
- log1p transformatsiya (summalar juda qiyshiq)
- StandardScaler
- 3-7 segment (boshqariladigan)
- har segment > 5%
- segmentlarni NOM bilan atash (marketing tili)RFM ni bazaviy natija sifatida qo'ying: u sodda, tushunarli va ko'pincha klasterlashdan yomon emas. Klasterlash RFM dan sezilarli yaxshi bo'lmasa, RFM ni tanlang.
2.2. Mavzu modellashtirish
Hujjat-so'z matritsasini ikkiga ajratish:
X (hujjat x so'z) ~ W (hujjat x mavzu) @ H (mavzu x so'z)
NMF (Non-negative Matrix Factorization):
+ barcha qiymatlar MANFIY EMAS -> talqin oson
+ TF-IDF bilan yaxshi ishlaydi
+ tez
sklearn: NMF(n_components=20, init="nndsvda")
LDA (Latent Dirichlet Allocation):
+ ehtimollik modeli, generativ
+ XOM SANOQ bilan ishlaydi (TF-IDF emas)
- sekinroq, parametrlarga sezgir
sklearn: LatentDirichletAllocation(n_components=20)
BAHOLASH: koherentlik (mavzu so'zlari birga uchraydimi), tushunarlilikNMF odatda amaliy tanlov: u tezroq, TF-IDF bilan ishlaydi va mavzulari ko'pincha tushunarliroq. LDA nazariy jihatdan chiroyliroq, lekin sozlash ko'proq vaqt oladi.
2.3. Tavsiya tizimi asoslari
Foydalanuvchi-mahsulot matritsasini faktorlash:
R (foydalanuvchi x mahsulot) ~ U (foydalanuvchi x omil) @ V^T
omillar = yashirin xususiyatlar (janr, narx darajasi, uslub)
bo'sh kataklar BASHORAT qilinadi
sklearn:
TruncatedSVD - siyrak matritsada ishlaydi
NMF - manfiy bo'lmagan reytinglar uchun
MUHIM: haqiqiy tavsiya tizimlari murakkabroq
implicit feedback, sovuq boshlash, vaqt, kontekst
ixtisoslashgan kutubxonalar: implicit, LightFM, Surprise
BAHOLASH: precision@k, recall@k, NDCG - aniqlik emasMatritsani faktorlash — tavsiya tizimining faqat yadrosi: real tizimda sovuq boshlash (yangi foydalanuvchi), xilma-xillik va yangilik muammolari ham hal qilinishi kerak.
2.4. Siqish va kvantlash
1. PCA siqish: X ~ Z @ components_
saqlanadi: Z (n x k) + components_ (k x p)
foyda: p >> k bo'lganda
2. VEKTOR KVANTLASH (K-means bilan):
har nuqtani eng yaqin MARKAZ bilan almashtirish
saqlanadi: markazlar (k x p) + yorliqlar (n ta indeks)
tasvir siqishda: ranglar palitrasi
3. MAHSULOT KVANTLASH (product quantization):
vektorni bo'laklarga bo'lib, har bo'lakni alohida kvantlash
vektor qidiruv tizimlarida (FAISS) standart
Baholash: siqish nisbati va qayta tiklash xatosi (MSE, PSNR)Vektor kvantlash — K-means ning eng eski amaliy qo'llanilishi: 16 mln rangni 32 ta rangga tushirish tasvirni 3 barobardan ko'proq siqadi va ko'z bilan farq deyarli sezilmaydi.
2.5. Belgi muhandisligi
# 1. Klaster yorlig'i - yangi kategoriyali belgi
X["klaster"] = KMeans(8, n_init=10, random_state=0).fit_predict(Xs)
# 2. Markazgacha masofalar - k ta yangi sonli belgi
masofalar = km.transform(Xs) # (n, k)
# 3. PCA komponentlari - shovqinsiz belgilar
X_yangi = np.column_stack([X, PCA(5).fit_transform(Xs)])
# 4. Anomaliya bali - yangi belgi
X["anomaliya"] = -IsolationForest().fit(X).score_samples(X)
# 5. GMM ehtimolliklari - yumshoq segment belgilari
X_yangi = np.column_stack([X, gmm.predict_proba(Xs)])Klaster yorlig'i belgi sifatida — nazoratsiz usullarning nazoratli modelga eng oddiy hissasi. Lekin buni Pipeline ichida qiling, aks holda leakage bo'ladi 12.9-bob.
2.6. Qaysi vazifada qaysi mezon
VAZIFA MEZON ALGORITM
segmentatsiya konversiya, tushunarlilik K-means, GMM
mavzu modellashtirish koherentlik, tushunarlilik NMF, LDA
tavsiya precision@k, NDCG TruncatedSVD, NMF
anomaliya precision@k, PR AUC IsolationForest, LOF
siqish hajm va MSE PCA, K-means
vizualizatsiya qo'shnilik saqlanishi t-SNE, UMAP, PCA
belgi muhandisligi keyingi modelning CV si hammasi
QOIDA: mezonni ALGORITMDAN OLDIN tanlangMezonni algoritmdan oldin tanlash — nazoratsiz loyihaning eng muhim qoidasi: aks holda siz "chiroyli" natijani tanlaysiz, foydali natijani emas.
2.7. Tuzoqlar
Asosiy tuzoqlar: segmentatsiyada RFM bazaviy natijasini o'tkazib yuborish; LDA ga TF-IDF berish (xom sanoq kerak); tavsiyani accuracy bilan baholash; klaster belgisini Pipeline tashqarisida qo'shish (leakage); mavzular sonini koherentliksiz tanlash; siqishda qayta tiklash xatosini o'lchamaslik; sovuq boshlashni hisobga olmaslik; mezonni algoritmdan keyin tanlash.
2.8. Mezon algoritmdan muhimroq
Segmentatsiyada RFM bazaviy natija, mezon — konversiya va tushunarlilik. Mavzu modellashtirishda NMF (TF-IDF bilan) amaliy tanlov, mezon — koherentlik. Tavsiyada matritsani faktorlash yadro, mezon — precision@k. Siqishda hajm va qayta tiklash xatosi muvozanati. Belgi muhandisligida klaster yorlig'i va masofalar — lekin Pipeline ichida. Mezonni algoritmdan oldin tanlang. Keyingi dars — amaliyot.
3. Tez ma'lumotnoma
from sklearn.decomposition import NMF, PCA, LatentDirichletAllocation, TruncatedSVD
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
# mavzu modellashtirish
tfidf = TfidfVectorizer(max_df=0.9, min_df=5)
X = tfidf.fit_transform(hujjatlar)
nmf = NMF(n_components=20, init="nndsvda", random_state=0).fit(X)
for i, mavzu in enumerate(nmf.components_):
print(i, [tfidf.get_feature_names_out()[j] for j in mavzu.argsort()[-8:]])
# LDA uchun XOM sanoq
sanoq = CountVectorizer(max_df=0.9, min_df=5).fit_transform(hujjatlar)
LatentDirichletAllocation(n_components=20, random_state=0).fit(sanoq)
# tavsiya
TruncatedSVD(n_components=50, random_state=0).fit(siyrak_matritsa)
QOIDA: mezonni oldin tanla · RFM bazaviy · LDA ga xom sanoq ·
belgini Pipeline ichidaQo'llanilish xulosasi
Segmentatsiya: RFM bazaviy, K-means/GMM, mezon = konversiya
Mavzular: NMF (TF-IDF) yoki LDA (xom sanoq), mezon = koherentlik
Tavsiya: matritsani faktorlash, mezon = precision@k
Siqish: PCA yoki vektor kvantlash, mezon = hajm va MSE4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14).
Misol 1 — Mijoz segmentatsiyasi: RFM va klasterlash
"""Bazaviy natija bilan taqqoslash (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
def yarat(seed: int = 11, n: int = 4000) -> pd.DataFrame:
"""Mijozlar: turli xulq-atvor naqshlari."""
rng = np.random.default_rng(seed)
tur = rng.choice(4, n, p=[0.35, 0.3, 0.2, 0.15])
profil = {
"recency": np.array([12.0, 60.0, 5.0, 120.0]),
"frequency": np.array([9.0, 2.0, 22.0, 1.5]),
"monetary": np.array([1_200_000.0, 400_000.0, 900_000.0, 2_500_000.0]),
}
df = pd.DataFrame({
nom: np.clip(markaz[tur] * rng.lognormal(0, 0.35, n), 0.5, None)
for nom, markaz in profil.items()
})
df["tur"] = tur
return df
def rfm_ball(df: pd.DataFrame) -> pd.DataFrame:
"""Har o'lchov bo'yicha 1-5 ball (kvintil)."""
natija = df.copy()
natija["R"] = pd.qcut(df["recency"], 5, labels=[5, 4, 3, 2, 1]).astype(int)
natija["F"] = pd.qcut(df["frequency"].rank(method="first"), 5,
labels=[1, 2, 3, 4, 5]).astype(int)
natija["M"] = pd.qcut(df["monetary"], 5, labels=[1, 2, 3, 4, 5]).astype(int)
return natija
def main() -> None:
df = yarat()
print("=== 1. Ma'lumot ===")
print(f" {len(df)} mijoz")
for nom in ["recency", "frequency", "monetary"]:
print(f" {nom:<12}: mediana {df[nom].median():>12,.0f}, "
f"qiyshiqlik {df[nom].skew():>6.2f}")
print("\n=== 2. RFM ballari (bazaviy) ===")
r = rfm_ball(df)
r["rfm_segment"] = np.select(
[(r["R"] >= 4) & (r["F"] >= 4),
(r["R"] >= 4) & (r["F"] < 4),
(r["R"] < 3) & (r["M"] >= 4),
(r["R"] < 3)],
["sodiq", "yangi", "yo'qolgan qimmatli", "uyquda"],
default="oddiy")
print(f" {'segment':<22} {'n':>7} {'ulush':>8} {'o_rt monetary':>16}")
for nom, guruh in r.groupby("rfm_segment"):
print(f" {nom:<22} {len(guruh):>7} {len(guruh) / len(r):>7.1%} "
f"{guruh['monetary'].mean():>16,.0f}")
print("\n=== 3. Klasterlash ===")
X = np.log1p(df[["recency", "frequency", "monetary"]].to_numpy())
Xs = StandardScaler().fit_transform(X)
print(f" {'k':>3} {'silhouette':>12} {'eng kichik %':>14}")
for k in range(2, 8):
yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xs)
print(f" {k:>3} {silhouette_score(Xs, yorliq):>12.4f} "
f"{np.bincount(yorliq).min() / len(Xs):>13.1%}")
print("\n=== 4. Ikki yondashuvni taqqoslash ===")
from sklearn.metrics import adjusted_rand_score
km = KMeans(4, n_init=10, random_state=0).fit_predict(Xs)
kod = {nom: i for i, nom in enumerate(sorted(r["rfm_segment"].unique()))}
rfm_yorliq = r["rfm_segment"].map(kod).to_numpy()
print(f" haqiqiy tur bilan ARI:")
print(f" RFM segmentlari: "
f"{adjusted_rand_score(df['tur'], rfm_yorliq):.4f}")
print(f" K-means (k=4): "
f"{adjusted_rand_score(df['tur'], km):.4f}")
print(f" ikkalasining o'zaro kelishuvi: "
f"{adjusted_rand_score(rfm_yorliq, km):.4f}")
print(f"\n {'klaster':>8} {'n':>7} {'recency':>10} {'frequency':>11} "
f"{'monetary':>14}")
for k in range(4):
m = km == k
print(f" {k:>8} {int(m.sum()):>7} {df.loc[m, 'recency'].mean():>10.1f} "
f"{df.loc[m, 'frequency'].mean():>11.1f} "
f"{df.loc[m, 'monetary'].mean():>14,.0f}")
print(" ⭐ RFM ni bazaviy natija sifatida qo'ying")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot ===
4000 mijoz
recency : mediana 17, qiyshiqlik 1.63
frequency : mediana 6, qiyshiqlik 1.69
monetary : mediana 943,194, qiyshiqlik 1.78
=== 2. RFM ballari (bazaviy) ===
segment n ulush o_rt monetary
oddiy 800 20.0% 1,115,212
sodiq 1259 31.5% 1,073,454
uyquda 1049 26.2% 422,950
yangi 341 8.5% 1,262,477
yo'qolgan qimmatli 551 13.8% 2,623,994
=== 3. Klasterlash ===
k silhouette eng kichik %
2 0.5404 44.5%
3 0.6238 13.9%
4 0.5271 13.9%
5 0.4702 13.9%
6 0.3718 13.8%
7 0.3493 9.6%
=== 4. Ikki yondashuvni taqqoslash ===
haqiqiy tur bilan ARI:
RFM segmentlari: 0.5667
K-means (k=4): 0.9377
ikkalasining o'zaro kelishuvi: 0.5753
klaster n recency frequency monetary
0 554 126.4 1.6 2,615,560
1 1390 13.0 9.3 1,294,462
2 1221 64.3 2.1 421,618
3 835 5.5 23.8 958,719
⭐ RFM ni bazaviy natija sifatida qo'yingNima ko'rsatdi: 2.1-bo'lim.
Misol 2 — Mavzu modellashtirish
"""NMF va LDA bilan mavzularni ajratish (real sklearn)."""
import numpy as np
from sklearn.decomposition import NMF, LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.metrics import adjusted_rand_score
def hujjatlar_yarat(seed: int = 4, n: int = 900):
"""Uch mavzu: sport, iqtisod, texnologiya."""
rng = np.random.default_rng(seed)
lugat = {
0: ["futbol", "musobaqa", "gol", "jamoa", "murabbiy", "chempionat",
"stadion", "o'yinchi", "ochko", "final"],
1: ["bank", "kredit", "investitsiya", "bozor", "narx", "eksport",
"soliq", "byudjet", "valyuta", "foiz"],
2: ["dastur", "server", "ma'lumot", "algoritm", "tarmoq", "qurilma",
"protsessor", "kod", "bulut", "xavfsizlik"],
}
umumiy = ["yangi", "katta", "bugun", "yil", "kun", "holat", "natija"]
matnlar, mavzular = [], []
for _ in range(n):
m = int(rng.integers(0, 3))
uzunlik = int(rng.integers(30, 90))
sozlar = list(rng.choice(lugat[m], int(uzunlik * 0.6)))
sozlar += list(rng.choice(umumiy, int(uzunlik * 0.25)))
# boshqa mavzudan biroz so'z (chalkashlik)
boshqa = int(rng.choice([x for x in [0, 1, 2] if x != m]))
sozlar += list(rng.choice(lugat[boshqa], int(uzunlik * 0.15)))
rng.shuffle(sozlar)
matnlar.append(" ".join(sozlar))
mavzular.append(m)
return matnlar, np.array(mavzular)
def eng_sozlar(komponent, nomlar, nechta: int = 6):
return [nomlar[i] for i in komponent.argsort()[-nechta:][::-1]]
def main() -> None:
matnlar, haqiqiy = hujjatlar_yarat()
print("=== 1. Korpus ===")
print(f" {len(matnlar)} hujjat, {len(set(haqiqiy))} mavzu")
print(f" o'rtacha uzunlik: "
f"{np.mean([len(m.split()) for m in matnlar]):.0f} so'z")
print("\n=== 2. NMF (TF-IDF bilan) ===")
tfidf = TfidfVectorizer(max_df=0.95, min_df=3)
Xt = tfidf.fit_transform(matnlar)
nomlar_t = tfidf.get_feature_names_out()
nmf = NMF(n_components=3, init="nndsvda", max_iter=3000,
tol=1e-5, random_state=0).fit(Xt)
W = nmf.transform(Xt)
for i, komp in enumerate(nmf.components_):
print(f" mavzu {i}: {eng_sozlar(komp, nomlar_t)}")
print(f" ARI: {adjusted_rand_score(haqiqiy, W.argmax(axis=1)):.4f}")
print("\n=== 3. LDA (xom sanoq bilan) ===")
sanoq = CountVectorizer(max_df=0.95, min_df=3)
Xs = sanoq.fit_transform(matnlar)
nomlar_s = sanoq.get_feature_names_out()
lda = LatentDirichletAllocation(n_components=3, max_iter=30,
learning_method="batch",
random_state=0).fit(Xs)
Wl = lda.transform(Xs)
for i, komp in enumerate(lda.components_):
print(f" mavzu {i}: {eng_sozlar(komp, nomlar_s)}")
print(f" ARI: {adjusted_rand_score(haqiqiy, Wl.argmax(axis=1)):.4f}")
print("\n=== 4. LDA ga TF-IDF berish xatosi ===")
lda_tfidf = LatentDirichletAllocation(n_components=3, max_iter=30,
learning_method="batch",
random_state=0).fit(Xt)
Wt = lda_tfidf.transform(Xt)
print(f" LDA + xom sanoq: ARI "
f"{adjusted_rand_score(haqiqiy, Wl.argmax(axis=1)):.4f}")
print(f" LDA + TF-IDF: ARI "
f"{adjusted_rand_score(haqiqiy, Wt.argmax(axis=1)):.4f}")
print(f" NMF + TF-IDF: ARI "
f"{adjusted_rand_score(haqiqiy, W.argmax(axis=1)):.4f}")
print(f"\n mavzular soni bo'yicha NMF qayta tiklash xatosi:")
for k in [2, 3, 5, 8]:
m = NMF(n_components=k, init="nndsvda", max_iter=3000,
tol=1e-5, random_state=0).fit(Xt)
print(f" k={k}: xato {m.reconstruction_err_:.4f}")
print(" ⭐ LDA xom sanoq, NMF TF-IDF bilan ishlaydi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Korpus ===
900 hujjat, 3 mavzu
o'rtacha uzunlik: 59 so'z
=== 2. NMF (TF-IDF bilan) ===
mavzu 0: ['dastur', 'kod', 'server', 'tarmoq', 'bulut', 'qurilma']
mavzu 1: ['gol', 'yinchi', 'futbol', 'ochko', 'musobaqa', 'final']
mavzu 2: ['valyuta', 'eksport', 'bozor', 'investitsiya', 'byudjet', 'narx']
ARI: 1.0000
=== 3. LDA (xom sanoq bilan) ===
mavzu 0: ['byudjet', 'investitsiya', 'valyuta', 'soliq', 'bozor', 'eksport']
mavzu 1: ['gol', 'final', 'ochko', 'jamoa', 'futbol', 'musobaqa']
mavzu 2: ['dastur', 'ma', 'lumot', 'server', 'xavfsizlik', 'kod']
ARI: 1.0000
=== 4. LDA ga TF-IDF berish xatosi ===
LDA + xom sanoq: ARI 1.0000
LDA + TF-IDF: ARI 1.0000
NMF + TF-IDF: ARI 1.0000
mavzular soni bo'yicha NMF qayta tiklash xatosi:
k=2: xato 19.2817
k=3: xato 14.6167
k=5: xato 13.8872
k=8: xato 12.9673
⭐ LDA xom sanoq, NMF TF-IDF bilan ishlaydiNima ko'rsatdi: 2.2-bo'lim.
Misol 3 — Tavsiya va siqish
"""Matritsani faktorlash va vektor kvantlash (real numpy/sklearn)."""
import numpy as np
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA, TruncatedSVD
from sklearn.metrics import mean_squared_error
def reytinglar(seed: int = 6, n_foyd: int = 500, n_mahsulot: int = 200,
n_omil: int = 5, zichlik: float = 0.05):
"""Yashirin omillarga asoslangan reytinglar."""
rng = np.random.default_rng(seed)
U = rng.normal(0, 1, (n_foyd, n_omil))
V = rng.normal(0, 1, (n_mahsulot, n_omil))
toliq = np.clip(3.0 + 0.7 * (U @ V.T), 1, 5)
kuzatilgan = rng.random(toliq.shape) < zichlik
return toliq, kuzatilgan
def main() -> None:
toliq, kuzatilgan = reytinglar()
print("=== 1. Reytinglar matritsasi ===")
print(f" {toliq.shape[0]} foydalanuvchi x {toliq.shape[1]} mahsulot")
print(f" kuzatilgan: {int(kuzatilgan.sum()):,} "
f"({kuzatilgan.mean():.1%})")
print(f" reyting: o'rtacha {toliq[kuzatilgan].mean():.3f}, "
f"std {toliq[kuzatilgan].std():.3f}")
print("\n=== 2. Matritsani faktorlash ===")
R = np.where(kuzatilgan, toliq, 0.0)
ortacha = toliq[kuzatilgan].mean()
Rm = np.where(kuzatilgan, toliq - ortacha, 0.0)
sinov = ~kuzatilgan
print(f" {'omillar':>9} {'sinov RMSE':>12} {'bazaviy (o_rtacha)':>20}")
bazaviy = np.sqrt(mean_squared_error(toliq[sinov],
np.full(sinov.sum(), ortacha)))
for k in [2, 5, 10, 20, 50]:
svd = TruncatedSVD(n_components=k, random_state=0).fit(Rm)
tiklangan = svd.transform(Rm) @ svd.components_ + ortacha
rmse = np.sqrt(mean_squared_error(toliq[sinov], tiklangan[sinov]))
print(f" {k:>9} {rmse:>12.4f} {bazaviy:>20.4f}")
print("\n=== 3. precision@k bilan baholash ===")
svd = TruncatedSVD(n_components=10, random_state=0).fit(Rm)
bashorat = svd.transform(Rm) @ svd.components_ + ortacha
yoqqan = toliq >= 4.0 # "yoqdi" deb hisoblanadi
natijalar = []
for foyd in range(len(toliq)):
nomzod = np.where(~kuzatilgan[foyd])[0]
if len(nomzod) < 10 or yoqqan[foyd, nomzod].sum() == 0:
continue
tartib = nomzod[np.argsort(-bashorat[foyd, nomzod])]
natijalar.append([yoqqan[foyd, tartib[:k]].mean() for k in [5, 10, 20]])
natijalar = np.array(natijalar)
asosiy = yoqqan[~kuzatilgan].mean()
print(f" tasodifiy tavsiya (bazaviy): {asosiy:.4f}")
for i, k in enumerate([5, 10, 20]):
print(f" precision@{k}: {natijalar[:, i].mean():.4f} "
f"({natijalar[:, i].mean() / asosiy:.2f}x bazaviydan)")
print("\n=== 4. Vektor kvantlash bilan siqish ===")
rng = np.random.default_rng(0)
# "tasvir": 200x200 piksel, RGB
balandlik, kenglik = 200, 200
asos = rng.normal(0, 1, (6, 3))
hudud = rng.integers(0, 6, (balandlik, kenglik))
tasvir = np.clip(128 + 60 * asos[hudud] + rng.normal(0, 12,
(balandlik, kenglik, 3)),
0, 255)
piksel = tasvir.reshape(-1, 3)
print(f" tasvir: {balandlik}x{kenglik}, "
f"{len(np.unique(piksel.round().astype(int), axis=0)):,} noyob rang")
print(f" {'ranglar':>9} {'MSE':>10} {'hajm (KB)':>12} {'siqish':>9}")
asl_hajm = piksel.size * 1 / 1024 # 1 bayt/kanal
for k in [2, 4, 8, 16, 32]:
km = KMeans(k, n_init=3, random_state=0).fit(piksel)
siqilgan = km.cluster_centers_[km.labels_]
bit = int(np.ceil(np.log2(k)))
hajm = (len(piksel) * bit / 8 + k * 3) / 1024
print(f" {k:>9} {mean_squared_error(piksel, siqilgan):>10.2f} "
f"{hajm:>12.1f} {asl_hajm / hajm:>8.1f}x")
print(f" asl hajm: {asl_hajm:.1f} KB")
print(" ⭐ K-means - klassik siqish algoritmi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Reytinglar matritsasi ===
500 foydalanuvchi x 200 mahsulot
kuzatilgan: 4,932 (4.9%)
reyting: o'rtacha 2.982, std 1.215
=== 2. Matritsani faktorlash ===
omillar sinov RMSE bazaviy (o_rtacha)
2 1.2036 1.2249
5 1.1867 1.2249
10 1.1887 1.2249
20 1.1950 1.2249
50 1.2078 1.2249
=== 3. precision@k bilan baholash ===
tasodifiy tavsiya (bazaviy): 0.2347
precision@5: 0.6320 (2.69x bazaviydan)
precision@10: 0.5900 (2.51x bazaviydan)
precision@20: 0.5457 (2.33x bazaviydan)
=== 4. Vektor kvantlash bilan siqish ===
tasvir: 200x200, 34,969 noyob rang
ranglar MSE hajm (KB) siqish
2 1154.81 4.9 24.0x
4 202.55 9.8 12.0x
8 118.35 14.7 8.0x
16 83.98 19.6 6.0x
32 53.90 24.5 4.8x
asl hajm: 117.2 KB
⭐ K-means - klassik siqish algoritmiNima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 4 — Belgi muhandisligi
"""Nazoratsiz usullar nazoratli modelga hissa qo'shadi (real sklearn)."""
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.ensemble import HistGradientBoostingClassifier, IsolationForest
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import StratifiedKFold, cross_val_score, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
class KlasterBelgilari(BaseEstimator, TransformerMixin):
"""Klaster markazlarigacha masofalarni belgi sifatida qo'shadi."""
def __init__(self, n_clusters: int = 8, random_state: int = 0):
self.n_clusters = n_clusters
self.random_state = random_state
def fit(self, X, y=None):
self.sc_ = StandardScaler().fit(X)
self.km_ = KMeans(self.n_clusters, n_init=10,
random_state=self.random_state).fit(
self.sc_.transform(X))
return self
def transform(self, X):
Xs = self.sc_.transform(X)
return np.column_stack([X, self.km_.transform(Xs)])
def yarat(seed: int = 15, n: int = 5000, p: int = 10):
"""Sinf klasterlar ichida joylashgan - klaster belgisi foydali."""
rng = np.random.default_rng(seed)
guruh = rng.integers(0, 5, n)
markazlar = rng.normal(0, 3.0, (5, p))
X = markazlar[guruh] + rng.normal(0, 1.0, (n, p))
# har guruhda o'z qoidasi
kuch = np.zeros(n)
for g in range(5):
m = guruh == g
belgi = g % p
kuch[m] = (1.0 if g % 2 == 0 else -1.0) * X[m, belgi]
y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
return X, y
def main() -> None:
X, y = yarat()
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
stratify=y)
cv = StratifiedKFold(4, shuffle=True, random_state=0)
def model():
return HistGradientBoostingClassifier(learning_rate=0.1, max_iter=200,
random_state=0)
print("=== 1. Bazaviy model ===")
asos = model().fit(Xtr, ytr)
a0 = roc_auc_score(yte, asos.predict_proba(Xte)[:, 1])
cv0 = cross_val_score(model(), Xtr, ytr, cv=cv, scoring="roc_auc").mean()
print(f" CV ROC AUC {cv0:.4f}, test {a0:.4f}")
print("\n=== 2. Klaster masofalari belgisi ===")
print(f" {'klasterlar':>11} {'CV ROC AUC':>12} {'test':>9}")
for k in [3, 5, 8, 15]:
quvur = Pipeline([("kb", KlasterBelgilari(k)), ("m", model())])
cvb = cross_val_score(quvur, Xtr, ytr, cv=cv, scoring="roc_auc").mean()
quvur.fit(Xtr, ytr)
a = roc_auc_score(yte, quvur.predict_proba(Xte)[:, 1])
print(f" {k:>11} {cvb:>12.4f} {a:>9.4f}")
print("\n=== 3. PCA va anomaliya bali belgilari ===")
class QoshimchaBelgilar(BaseEstimator, TransformerMixin):
def __init__(self, pca_k: int = 3):
self.pca_k = pca_k
def fit(self, X, y=None):
self.sc_ = StandardScaler().fit(X)
self.p_ = PCA(self.pca_k, random_state=0).fit(self.sc_.transform(X))
self.izo_ = IsolationForest(n_estimators=100, random_state=0,
n_jobs=1).fit(X)
return self
def transform(self, X):
return np.column_stack([X, self.p_.transform(self.sc_.transform(X)),
-self.izo_.score_samples(X)])
quvur = Pipeline([("qb", QoshimchaBelgilar(3)), ("m", model())])
cvb = cross_val_score(quvur, Xtr, ytr, cv=cv, scoring="roc_auc").mean()
quvur.fit(Xtr, ytr)
print(f" PCA(3) + anomaliya bali: CV {cvb:.4f}, "
f"test {roc_auc_score(yte, quvur.predict_proba(Xte)[:, 1]):.4f}")
print("\n=== 4. Leakage: Pipeline ichida va tashqarisida ===")
# NOTO'G'RI: klasterlash butun ma'lumotda
sc_hammasi = StandardScaler().fit(X)
km_hammasi = KMeans(8, n_init=10, random_state=0).fit(
sc_hammasi.transform(X))
X_notogri = np.column_stack([X, km_hammasi.transform(sc_hammasi.transform(X))])
Xn_tr = X_notogri[:len(Xtr)]
cv_notogri = cross_val_score(model(), Xn_tr, ytr, cv=cv,
scoring="roc_auc").mean()
# TO'G'RI: Pipeline ichida
quvur = Pipeline([("kb", KlasterBelgilari(8)), ("m", model())])
cv_togri = cross_val_score(quvur, Xtr, ytr, cv=cv,
scoring="roc_auc").mean()
print(f" butun ma'lumotda klasterlab (noto'g'ri): CV {cv_notogri:.4f}")
print(f" Pipeline ichida (to'g'ri): CV {cv_togri:.4f}")
print(f" farq: {cv_notogri - cv_togri:+.4f}")
print(" (bu vazifada klasterlash y ni ko'rmaydi, shuning uchun farq kichik;")
print(" lekin target encoding kabi usullarda u katta bo'ladi - 12.9)")
print(" ⭐ Nazoratsiz belgilarni Pipeline ichida yarating")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bazaviy model ===
CV ROC AUC 0.9218, test 0.9128
=== 2. Klaster masofalari belgisi ===
klasterlar CV ROC AUC test
3 0.9217 0.9121
5 0.9217 0.9087
8 0.9227 0.9096
15 0.9240 0.9117
=== 3. PCA va anomaliya bali belgilari ===
PCA(3) + anomaliya bali: CV 0.9217, test 0.9088
=== 4. Leakage: Pipeline ichida va tashqarisida ===
butun ma'lumotda klasterlab (noto'g'ri): CV 0.4806
Pipeline ichida (to'g'ri): CV 0.9227
farq: -0.4421
(bu vazifada klasterlash y ni ko'rmaydi, shuning uchun farq kichik;
lekin target encoding kabi usullarda u katta bo'ladi - 12.9)
⭐ Nazoratsiz belgilarni Pipeline ichida yaratingNima ko'rsatdi: 2.5-bo'lim.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Klasterlash RFM dan yaxshiroq" | Tekshiring, ko'pincha teng |
| "LDA ga TF-IDF beriladi" | Xom sanoq |
| "NMF va LDA bir xil" | Turli model, turli kirish |
| "Tavsiyani accuracy bilan baholash" | precision@k, NDCG |
| "Matritsani faktorlash = tavsiya tizimi" | Faqat yadro |
| "Klaster belgisi har doim foydali" | CV bilan tekshiring |
| "Belgini oldindan hisoblash mumkin" | Pipeline ichida |
| "Siqishda faqat hajm muhim" | Xato ham |
6. Keng tarqalgan xatolar va yechimlari
1. Bazaviy natijasiz segmentatsiya
KMeans(5).fit(Xs) # RFM bilan solishtirilmagan # ⚠️
# avval RFM, keyin klasterlash, keyin taqqoslash # ✅2. LDA ga TF-IDF
LatentDirichletAllocation(20).fit(tfidf_matritsa) # ⚠️
LatentDirichletAllocation(20).fit(count_matritsa) # ✅3. Summalarni transformatsiyasiz klasterlash
KMeans(4).fit(StandardScaler().fit_transform(df[["monetary"]])) # ⚠️
KMeans(4).fit(StandardScaler().fit_transform(np.log1p(df[["monetary"]]))) # ✅4. Tavsiyani RMSE bilan baholash
mean_squared_error(haqiqiy, bashorat) # foydalanuvchi ko'rmaydi # ⚠️
# precision@10, recall@10, NDCG # ✅5. Belgini Pipeline tashqarisida
X["klaster"] = KMeans(8).fit_predict(Xs); cross_val_score(m, X, y) # ⚠️
Pipeline([("kb", KlasterBelgilari(8)), ("m", model)]) # ✅6. Siqishda xatoni o'lchamaslik
# "32 rangga tushirdik, 5x siqildi" # ⚠️
# MSE/PSNR ni ham keltiring # ✅7. Mavzular sonini tasodifan tanlash
NMF(n_components=20) # 20 qayerdan? # ⚠️
# reconstruction_err_ + koherentlik + muharrir bahosi # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 16.2-dars (o'tilgan): K-means
- 16.8-dars (o'tilgan): PCA
- 16.10-dars (o'tilgan): Anomaliya
- 12.9-dars (o'tilgan): Leakage
- 16.12-dars: Amaliyot
8. Eng yaxshi amaliyotlar
Mezonni algoritmdan oldin tanlang.
Bazaviy natija quring (RFM).
Qiyshiq summalarni log1p qiling.
LDA ga xom sanoq bering.
Tavsiyani precision@k bilan baholang.
Belgilarni Pipeline ichida yarating.
Siqishda xatoni ham keltiring.
Mavzularni odamga tekshirtiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # RFM nimani anglatadi?
2. # segmentatsiyada nechta segment?
3. # summalarni qanday transformatsiya qilish kerak?
4. # NMF ning afzalligi?
5. # NMF qaysi kirish bilan?
6. # LDA qaysi kirish bilan?
7. # tavsiyada matritsa qanday ajratiladi?
8. # tavsiya metrikasi?
9. # vektor kvantlash nima?
10. # klaster belgisi qanday qo'shiladi?
11. # leakage dan qanday saqlanish kerak?
12. # mezon qachon tanlanadi?Javoblar
- Recency, Frequency, Monetary
- 3-7
- log1p
- Manfiy emas, talqin oson
- TF-IDF
- Xom sanoq
- U @ V^T
- precision@k, NDCG
- Nuqtani markaz bilan almashtirish
- Yorliq yoki masofalar
- Pipeline ichida
- Algoritmdan oldin
Vazifa 2: Xatolarni tuzating
1. LatentDirichletAllocation(20).fit(tfidf_matritsa)
2. KMeans(4).fit(StandardScaler().fit_transform(df[["monetary"]]))
3. mean_squared_error(haqiqiy, bashorat) # tavsiya
4. X["klaster"] = KMeans(8).fit_predict(Xs); cross_val_score(m, X, y)
5. NMF(n_components=20) # 20 qayerdan?Javoblar
1. LatentDirichletAllocation(20).fit(count_matritsa)
2. KMeans(4).fit(StandardScaler().fit_transform(np.log1p(df[["monetary"]])))
3. # precision@10, recall@10, NDCG
4. Pipeline([("kb", KlasterBelgilari(8)), ("m", model)])
5. # reconstruction_err_ + koherentlik + muharrir bahosiVazifa 3: Segmentatsiya
Modellang:
- Ma'lumot
- RFM
- Klasterlash
- Taqqoslash
Vazifa 4: Mavzular
Modellang:
- Korpus
- NMF
- LDA
- Kirish turi
Vazifa 5: Tavsiya va siqish
Modellang:
- Reytinglar
- Faktorlash
- precision@k
- Kvantlash
Vazifa 6: Belgi muhandisligi
Modellang:
- Bazaviy
- Klaster masofalari
- PCA va anomaliya
- Leakage
Vazifa 7: O'ylash
Mavzu modellashtirish 20 ta mavzu berdi. Ulardan 14 tasi tushunarli, 6 tasi esa tasodifiy so'zlar aralashmasi. Nima qilish kerak?
Javob
Qisqa javob: bu normal holat — mavzu modellari har doim bir nechta "axlat" mavzu beradi. Uch yo'l bor: mavzular sonini kamaytirish, matn tayyorlashni yaxshilash yoki yomon mavzularni qabul qilib, ularni ishlatmaslik.
1. Nega "axlat" mavzular paydo bo'ladi
| Sabab | Belgi |
|---|---|
k juda katta |
Mavzular bo'linib ketgan |
| Tayyorlash yetarli emas | Stop-so'zlar, raqamlar, xatolar |
| Korpus bir xil emas | Turli janr, til, uzunlik |
| Kam uchraydigan hujjatlar | "Qolgan hammasi" mavzusi |
2. Tayyorlashni yaxshilash (odatda eng ko'p foyda)
min_df=5— juda kam uchraydigan so'zlarni chiqarishmax_df=0.9— deyarli hamma joyda uchraydigan so'zlarni chiqarish- Stop-so'zlar ro'yxati (o'zbek tili uchun alohida)
- Lemmatizatsiya yoki stemming
- Juda qisqa hujjatlarni chiqarish
3. k ni to'g'ri tanlash
1. k ni 5 dan 40 gacha oshirib, reconstruction_err_ ni chizing
2. Har k uchun 5-10 ta mavzuni muharrirga ko'rsating
3. "Tushunarli mavzular ulushi" ni o'lchang
4. Shu ulush tushib ketadigan nuqtadan oldingi k ni olingKoherentlik metrikasi (c_v, u_mass) avtomatlashtiradi, lekin odam bahosi ishonchliroq.
4. Yomon mavzularni boshqarish
- Ularni belgilab qo'ying ("aralash", "tasnifsiz")
- Shu mavzuga tushgan hujjatlarni qo'lda ko'rib chiqing
- Ko'pincha ular haqiqatan aralash hujjatlar bo'lib chiqadi
- 70-80% tushunarli mavzu — yaxshi natija
5. Xulosa
- Axlat mavzular normal
- Avval tayyorlashni yaxshilang
kni tushunarlilik bo'yicha tanlang- Qolganini belgilab, alohida ko'rib chiqing
Nimani mustahkamlaydi: 2.2, 2.6-bo'limlar.
Xulosa
Bu darsda nazoratsiz o'rganishning qo'llanilishini o'rgandik.
Eng muhim uch fikr:
Mezonni algoritmdan oldin tanlang. Segmentatsiyada mezon — konversiya va tushunarlilik, mavzu modellashtirish — koherentlik, tavsiya — precision@k, siqish — hajm va xato muvozanati. Mezonni keyin tanlasangiz, "chiroyli" natijani tanlaysiz, foydalisini emas. Segmentatsiyada RFM ni bazaviy natija qiling: klasterlash undan sezilarli yaxshi bo'lmasa, soddaroq usulni oling.
Kirish turi modelga mos bo'lishi kerak. NMF — TF-IDF bilan (manfiy emas, talqin oson, tez), LDA — xom sanoq bilan (ehtimollik modeli). LDA ga TF-IDF berish — keng tarqalgan va jim xato: model ishlaydi, lekin natija yomonroq bo'ladi. Qiyshiq summalarni esa klasterlashdan oldin
log1pbilan transformatsiya qiling.Nazoratsiz belgilarni Pipeline ichida yarating. Klaster yorlig'i, markazlargacha masofalar, PCA komponentlari va anomaliya bali — bularning hammasi nazoratli model uchun foydali belgi bo'lishi mumkin. Lekin ularni butun ma'lumotda oldindan hisoblab, keyin CV qilish — leakage 12.9-bob.
TransformerMixinbilan o'z transformeringizni yozib, uniPipelinega qo'ying.
Keyingi darsda amaliyot: 16-qism bo'yicha to'liq loyiha.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!