4-qism · Ma'lumotlar bilan ishlash·19-bob
NumPy: raqamli hisoblashning poydevori
ndarray nima va nega u Python ro'yxatidan 20–100 baravar tez, dtype va shape, indekslash va boolean maskalar, view va copy, broadcasting, o'qlar (axis) bo'yicha agregatsiya, chiziqli algebra, tasodifiy sonlar va embedding'lar bilan amaliyot.
NumPy — Python'dagi butun ilmiy va ML ekotizimining poydevori. Pandas ichida NumPy massivlari, scikit-learn NumPy massivlarini qabul qiladi, PyTorch tensorlari NumPy massivlariga deyarli bir xil ishlaydi (va bir-biriga aylanadi), rasmlar — NumPy massivlari, embedding'lar — NumPy massivlari. Bu bobni yaxshi o'zlashtirsangiz, PyTorch'ga o'tish ancha oson bo'ladi: tensor operatsiyalarining 80% i — shu yerdagi g'oyalar.
uv add numpyimport numpy as np # har doim shu taxallus bilanNumPy massivlari, indekslash, matematik amallar va broadcasting'ga amaliy kirish.
1. Nega NumPy: tezlik va xotira#
1-bobda ko'rgan edik: sof Python'da har bir son — alohida obyekt (28 bayt), ro'yxat esa ularga ko'rsatkichlar massivi, va har bir amalda tip tekshiriladi. NumPy massivi esa — xotirada ketma-ket joylashgan, bir xil tipdagi xom sonlar:
- Bitta uzluksiz xotira bloki
- Hamma elementlar bir xil tipda (masalan, float64 — 8 bayt)
- Amallar C'da, bitta tsiklda — tip bir marta tekshiriladi
- SIMD protsessor ko'rsatmalari, BLAS kutubxonalari
- Ko'rsatkichlar massivi + har bir son alohida obyekt
- Har element istalgan tipda bo'lishi mumkin
- Har bir amalda interpretator tip tekshiradi
- Million son ≈ 36 MB (NumPy'da ≈ 8 MB)
Real o'lchov (million son kvadratlari yig'indisi):
import time
import numpy as np
n = 1_000_000
lst = list(range(n))
arr = np.arange(n)
t = time.perf_counter(); s1 = sum(x * x for x in lst); print(time.perf_counter() - t) # ~0.038 s
t = time.perf_counter(); s2 = (arr * arr).sum(); print(time.perf_counter() - t) # ~0.0016 s~25 baravar tezroq, va bu oddiy amal uchun. Murakkabroq amallarda (matritsa ko'paytmasi) farq yuzlab–minglab baravarga yetadi. Bu usul — vektorlashtirish (vectorization): siklni Python'da yozish o'rniga, butun massiv ustida bitta amal.
2. ndarray — asosiy tushunchalar#
a = np.array([1, 2, 3])
a.dtype # dtype('int64') — elementlar tipi
a.shape # (3,) — har o'lchamdagi uzunlik (tuple!)
a.ndim # 1 — o'lchamlar soni
a.size # 3 — jami elementlar
a.nbytes # 24 — 3 × 8 bayt
m = np.arange(12).reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
m.shape # (3, 4) — 3 qator, 4 ustun
m.T.shape # (4, 3) — transpozeShape — NumPy va PyTorch'ning eng muhim tushunchasi. ML'dagi
xatolarning katta qismi — shape mos kelmasligi. Har doim shape haqida
o'ylang va kerak bo'lsa print(x.shape) qiling.
| Ma'lumot | Odatiy shape |
|---|---|
| Bitta embedding | (768,) |
| Embedding'lar to'plami | (n_docs, 768) |
| Jadval (tabular) | (n_samples, n_features) |
| Kulrang rasm | (H, W) |
| Rangli rasm | (H, W, 3) — NumPy/PIL; (3, H, W) — PyTorch |
| Rasmlar batch'i | (batch, 3, H, W) |
| Matn token'lari batch'i | (batch, seq_len) |
| Transformer yashirin holati | (batch, seq_len, d_model) |
dtype#
np.array([1, 2.5]).dtype # float64 — bitta float hammasini float qiladi
np.array([1, "a"]).dtype # <U21 — satr! (sonlar satrga aylandi — odatda xato belgisi)
np.zeros(3, dtype=np.float32) # ML'da ko'pincha float32 — xotira 2× kam, GPU uchun standart
a.astype(np.float32) # tipni o'zgartirish (yangi massiv)Massiv yaratish#
np.zeros((2, 3)) # nollar
np.ones(3) # birlar
np.full((2, 2), 7) # bir xil qiymat
np.eye(3) # birlik matritsa
np.arange(0, 1, 0.25) # [0. 0.25 0.5 0.75] — range kabi, qadam bilan
np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.] — 5 ta teng taqsimlangan nuqta (oxiri kiradi)
np.empty((1000, 768)) # ishga tushirilmagan — tez, lekin ichida "axlat"
np.zeros_like(a) # a bilan bir xil shape va dtype3. Indekslash va slicing#
1D — ro'yxat kabi. Ko'p o'lchamda — har o'lcham uchun vergul bilan:
m = np.arange(12).reshape(3, 4)
m[1] # [4 5 6 7] — 1-qator
m[1, 2] # 6 — 1-qator, 2-ustun (m[1][2] ham ishlaydi, lekin sekinroq)
m[:, 1] # [1 5 9] — 1-ustun (hamma qatorlar)
m[:2, 1:3] # [[1 2] [5 6]] — qism-matritsa
m[-1] # oxirgi qator
m[::2] # har ikkinchi qatorBoolean maskalar — eng kuchli vosita#
x = np.array([3, -1, 4, -1, 5])
x > 0 # [ True False True False True] — mask
x[x > 0] # [3 4 5] — filtrlash
(x > 0).sum() # 3 — nechtasi (True = 1)
(x > 0).mean() # 0.6 — ulushi
x[(x > 0) & (x < 5)] # [3 4] — & (va), | (yoki), ~ (emas); QAVSLAR SHART
np.where(x > 0, x, 0) # [3 0 4 0 5] — shartli tanlash (ReLU!)
x[x < 0] = 0 # mask bo'yicha qiymat berishFancy indexing — indekslar ro'yxati bilan#
x[[0, 2, 4]] # [3 4 5]
labels = np.array([2, 0, 1])
probs = np.array([[0.1, 0.2, 0.7],
[0.8, 0.1, 0.1],
[0.3, 0.4, 0.3]])
probs[np.arange(3), labels] # [0.7 0.8 0.4] — har qatordan to'g'ri sinf ehtimoliOxirgi qator — cross-entropy loss hisoblashning asosi.
4. View va copy — 2-bobning NumPy versiyasi#
Slicing nusxa yaratmaydi — view qaytaradi: o'sha xotiraga boshqa "oyna". View orqali o'zgartirish asl massivni o'zgartiradi:
m = np.arange(12).reshape(3, 4)
row = m[0] # view
row[0] = 100
m[0, 0] # 100 — asl massiv o'zgardi!
safe = m[0].copy() # haqiqiy nusxa
safe[0] = 99
m[0, 0] # 100 — o'zgarmadi| Amal | Natija |
|---|---|
Slicing a[1:3], a[:, 0] | View |
reshape, .T, ravel (odatda) | View |
Boolean mask a[a > 0] | Copy |
Fancy indexing a[[0, 2]] | Copy |
Arifmetika a + 1 | Yangi massiv |
.copy() | Copy |
Python ro'yxatida lst[1:3] — nusxa; NumPy'da — view. Bu farq ko'p
odamni aldaydi. Shubha bo'lsa: np.shares_memory(a, b).
5. Vektorlashgan amallar va ufunc'lar#
Arifmetika har bir element uchun bajariladi:
a = np.array([1.0, 2.0, 3.0])
a + 1, a * 2, a ** 2, 1 / a
np.sqrt(a), np.exp(a), np.log(a), np.abs(a) # "universal functions" (ufunc)
np.maximum(a, 2) # [2. 2. 3.] — element bo'yicha max
np.clip(a, 1.5, 2.5) # [1.5 2. 2.5]Sof Python sikli yozishdan oldin har doim so'rang: "buni bitta massiv amali bilan qilsa bo'ladimi?" — deyarli har doim bo'ladi.
# ❌ Python sikli
result = np.empty(len(x))
for i in range(len(x)):
result[i] = max(x[i], 0)
# ✅ Vektorlashgan
result = np.maximum(x, 0)6. Agregatsiya va axis#
m = np.arange(12).reshape(3, 4)
m.sum() # 66 — hammasi
m.sum(axis=0) # [12 15 18 21] — USTUNLAR bo'yicha (qatorlar "yig'iladi")
m.sum(axis=1) # [ 6 22 38] — QATORLAR bo'yicha
m.mean(axis=0), m.std(axis=0), m.min(axis=1), m.max()
m.argmax(axis=1) # har qatordagi maksimum indeksi — sinf bashorati!axisni eslab qolish usuli: axis=k — k-o'lcham yo'qoladi. Shape
(3, 4) massivda sum(axis=0) → shape (4,); sum(axis=1) → (3,).
keepdims=True — yo'qolgan o'lchamni 1 sifatida saqlaydi, broadcasting
uchun qulay: m.sum(axis=1, keepdims=True) → shape (3, 1).
NaN bilan: np.mean([1, np.nan, 3]) → nan; np.nanmean(...) → 2.0.
7. Broadcasting#
Turli shape'li massivlar o'rtasida amal qanday bajariladi?
A = np.arange(6).reshape(2, 3) # (2, 3)
b = np.array([10, 20, 30]) # (3,)
A + b
# [[10 21 32]
# [13 24 35]] — b har bir qatorga qo'shildiQoida: shape'lar o'ngdan solishtiriladi; har bir o'lcham juftligi yo teng, yo ulardan biri 1 bo'lishi kerak (yoki o'lcham yo'q). 1 bo'lgan o'lcham boshqasiga "cho'ziladi" (xotirada nusxalanmasdan).
| A shape | B shape | Natija | Izoh |
|---|---|---|---|
(2, 3) | (3,) | (2, 3) | B har qatorga |
(2, 3) | (2, 1) | (2, 3) | B har ustunga |
(n, d) | (d,) | (n, d) | Har namunadan o'rtachani ayirish |
(n, 1) | (1, m) | (n, m) | "Tashqi" amal — hamma juftliklar |
(2, 3) | (2,) | ❌ | 3 ≠ 2 — xato |
A + np.array([1, 2])
# ValueError: operands could not be broadcast together with shapes (2,3) (2,)
A + np.array([[1], [2]]) # ✅ (2, 1) — har qatorga o'z soniAmaliy misol: standartlashtirish (z-score)#
rng = np.random.default_rng(42)
X = rng.normal(loc=5, scale=2, size=(1000, 3)) # 1000 namuna, 3 xususiyat
mu = X.mean(axis=0) # (3,)
sigma = X.std(axis=0) # (3,)
Z = (X - mu) / sigma # (1000, 3) - (3,) → broadcasting
Z.mean(axis=0).round(6) # [0. 0. 0.]
Z.std(axis=0) # [1. 1. 1.]Bitta qator — sikllarsiz. scikit-learn'ning StandardScaleri ichkarida
aynan shuni qiladi.
8. Shape'ni o'zgartirish#
img = np.zeros((32, 32, 3))
img.reshape(-1).shape # (3072,) — -1: "qolganini o'zing hisobla"
img.reshape(32 * 32, 3).shape # (1024, 3) — piksellar ro'yxati
img[None].shape # (1, 32, 32, 3) — yangi o'lcham (batch)
np.expand_dims(img, 0).shape # xuddi shu
img.transpose(2, 0, 1).shape # (3, 32, 32) — HWC → CHW (PyTorch formati)
np.squeeze(np.zeros((1, 5, 1))).shape # (5,) — 1 o'lchamlarni olib tashlash
np.concatenate([a, b], axis=0) # mavjud o'q bo'yicha ulash
np.stack([a, b], axis=0) # YANGI o'q yaratib ulash
np.vstack, np.hstack # qulay qisqartmalar9. Chiziqli algebra#
X = np.array([[1.0, 2.0], [3.0, 4.0]])
W = np.array([[1.0, 0.0], [0.0, 2.0]])
X @ W # matritsa ko'paytmasi → [[1. 4.] [3. 8.]]
X * W # ELEMENT bo'yicha ko'paytma → [[1. 0.] [0. 8.]] — boshqa narsa!
np.dot([1, 2], [3, 4]) # 11 — skalyar ko'paytma
np.linalg.norm([3, 4]) # 5.0 — vektor uzunligi
np.linalg.inv(X) # teskari matritsa
np.linalg.solve(X, [1, 2]) # X @ x = b tenglamasini yechish (inv'dan barqarorroq)Neyron tarmoq qatlami — aynan shu: y = X @ W + b. Shape'lar:
(batch, in) @ (in, out) + (out,) → (batch, out).
10. Tasodifiy sonlar#
rng = np.random.default_rng(42) # ✅ zamonaviy API: alohida generator, seed bilan
rng.random(3) # [0, 1) oralig'ida
rng.integers(0, 10, size=5) # butun sonlar [0, 10)
rng.normal(0, 1, size=(2, 3)) # normal taqsimot
rng.choice(100, size=5, replace=False)
rng.permutation(5) # [0 1 4 2 3] — aralashtirilgan indekslar
rng.shuffle(arr) # joyidaEski kodlarda np.random.seed(42) va np.random.rand(...) ko'rasiz —
bu global holat (18-bobdagi random.seed muammosi). Yangi kodda
default_rng ishlating.
Train/test bo'linishi indekslar orqali:
idx = rng.permutation(len(X))
split = int(0.8 * len(X))
X_train, X_test = X[idx[:split]], X[idx[split:]]
y_train, y_test = y[idx[:split]], y[idx[split:]] # X va y bir xil indekslar bilan!11. Raqamli barqarorlik#
ML'da ko'p uchraydigan ikki muammo:
np.exp(1000.0) # inf — overflow (RuntimeWarning bilan)Softmaxni to'g'ridan-to'g'ri yozish xavfli. Barqaror versiya — maksimumni ayirish (matematik jihatdan natija o'zgarmaydi):
def softmax(logits: np.ndarray, axis: int = -1) -> np.ndarray:
z = logits - logits.max(axis=axis, keepdims=True)
e = np.exp(z)
return e / e.sum(axis=axis, keepdims=True)
softmax(np.array([2.0, 1.0, 0.1])) # [0.659 0.242 0.099]
softmax(np.array([1000.0, 1001.0])) # [0.269 0.731] — inf yo'qlog(0) → -inf muammosi uchun: np.log(p + 1e-12) yoki np.log1p,
np.clip(p, 1e-12, 1).
12. Amaliyot: embedding'lar bilan semantik qidiruv#
RAG tizimlarining yuragi — eng o'xshash hujjatlarni topish. Embedding'lar (matnlarning vektor ko'rinishi) tayyor deb hisoblaymiz:
import numpy as np
rng = np.random.default_rng(0)
doc_embeddings = rng.normal(size=(10_000, 768)).astype(np.float32) # 10k hujjat
query = rng.normal(size=768).astype(np.float32)
def normalize(x: np.ndarray) -> np.ndarray:
return x / np.linalg.norm(x, axis=-1, keepdims=True)
def top_k(query: np.ndarray, docs: np.ndarray, k: int = 5) -> tuple[np.ndarray, np.ndarray]:
"""Kosinus o'xshashlik bo'yicha eng yaqin k ta hujjat."""
sims = normalize(docs) @ normalize(query) # (10000, 768) @ (768,) → (10000,)
idx = np.argpartition(-sims, k)[:k] # O(n) — to'liq saralashdan tez
idx = idx[np.argsort(-sims[idx])] # faqat k tasini saralash
return idx, sims[idx]
idx, scores = top_k(query, doc_embeddings, k=5)
print(idx, scores.round(3))Bu kod 10 000 hujjat ichidan millisekundlarda qidiradi. Hisob: normalizatsiya
(broadcasting + axis), matritsa-vektor ko'paytmasi (@), argpartition
bilan top-k. Vektor ma'lumotlar bazalari (FAISS, pgvector, Qdrant) aynan
shu g'oyani millionlab vektorlar uchun indekslar bilan tezlashtiradi.
13. NumPy va boshqa kutubxonalar#
arr.tolist() # → Python ro'yxati (JSON uchun)
float(np.float64(1.5)) # → Python float (yoki .item())
np.save("emb.npy", arr); np.load("emb.npy") # tez binar saqlash
# PyTorch bilan (xotira umumiy bo'lishi mumkin!):
# t = torch.from_numpy(arr) arr = t.numpy()
# Pandas: df.to_numpy(), pd.DataFrame(arr, columns=[...])Nima noto'g'ri ketishi mumkin#
| Xato | Belgisi | Tuzatish |
|---|---|---|
| Python sikli massiv ustida | Sekinlik | Vektorlashgan amal |
| Slice'ni nusxa deb o'ylash | Asl ma'lumot o'zgardi | .copy() |
and/or massivlar bilan | truth value ... is ambiguous | &, |, ~ va qavslar |
* matritsa ko'paytmasi deb | Noto'g'ri natija, shape to'g'ri ko'rinishi mumkin | @ |
| Shape mos emas | operands could not be broadcast | print(a.shape, b.shape), reshape/None |
Kutilmagan broadcasting (n,) va (n, 1) | (n, n) massiv — jim xato! | Shape'larni tekshiring, assert |
| uint8/int8 to'lib ketishi | G'alati qiymatlar | astype(np.float32) |
np.exp katta son | inf, nan | Maksimumni ayirish (softmax) |
np.mean NaN bilan | nan | np.nanmean yoki tozalash |
np.random.seed global | Takrorlanmaydigan natija | np.random.default_rng(seed) |
json.dumps(np.float32(...)) | not JSON serializable | .item() / .tolist() |
1. Vektorlashtiring
Ikki nuqtalar to'plami A (n×2) va B (m×2) orasidagi barcha juftlik
masofalari matritsasini (n×m) avval ikki ichma-ich Python sikli bilan,
keyin sikllarsiz broadcasting bilan hisoblang. n = m = 1000 uchun vaqtni
solishtiring va natijalar bir xil ekanini np.allclose bilan tekshiring.
Maslahatni ko'rsatish
Masofalar: np.sqrt(((A[:, None, :] - B[None, :, :]) ** 2).sum(-1)) — broadcasting bilan (n, 1, d) - (1, m, d) → (n, m, d).
2. Metrikalar
y_true va y_pred (0/1 massivlar) berilgan. Sikllarsiz accuracy,
precision, recall, F1 hisoblang. Keyin ko'p sinfli holat uchun confusion
matrix yasang (np.add.at yoki np.bincount bilan). Natijani 22-bobda
scikit-learn bilan solishtiramiz.
Maslahatni ko'rsatish
TP = ((pred == 1) & (y == 1)).sum(); precision = TP / (TP + FP); confusion: np.zeros((k, k), int); np.add.at(cm, (y, pred), 1).
3. Mini chiziqli regressiya
rng bilan sun'iy ma'lumot yarating: y = 3*x1 - 2*x2 + 1 + shovqin.
Faqat NumPy bilan gradient descent orqali w va bni toping (MSE loss).
Natijani np.linalg.lstsq yechimi bilan solishtiring. Bu — neyron
tarmoqlar o'qitishning eng sodda shakli.
Maslahatni ko'rsatish
Gradient: grad_w = 2/n * X.T @ (X @ w + b - y); grad_b = 2/n * (X @ w + b - y).sum(). 500 qadam, lr=0.1.
4. Rasm bilan ishlash
(64, 64, 3) uint8 tasodifiy "rasm" yarating. (a) kulrangga aylantiring
(0.299 R + 0.587 G + 0.114 B), (b) [0, 1] ga normalizatsiya qiling,
(c) gorizontal aks ettiring ([:, ::-1]), (d) markazdan 32×32 kesing,
(e) 8 ta shunday rasmni (8, 3, 64, 64) PyTorch batch formatiga keltiring.
Har qadamda shape va dtype'ni chiqaring.
- 01ndarray — bir xil tipdagi sonlarning uzluksiz bloki; vektorlashtirish sof Python'dan 20–100× tez.
- 02shape — eng muhim tushuncha; dtype — ML'da ko'pincha float32; int'lar to'lib ketishi mumkin.
- 03Boolean mask: x[x > 0], &, |, ~ va qavslar; np.where — shartli tanlash.
- 04Slicing — view (asl ma'lumotni o'zgartiradi); mask va fancy indexing — copy.
- 05axis=k — k-o'lcham yo'qoladi; keepdims=True broadcasting uchun.
- 06Broadcasting: shape'lar o'ngdan solishtiriladi, teng yoki 1 bo'lishi kerak; (n,) va (n,1) dan ehtiyot bo'ling.
- 07@ — matritsa ko'paytmasi, * — element bo'yicha.
- 08default_rng(seed) — takrorlanuvchanlik; softmax'da maksimumni ayiring.
Mustahkamlash
Test va amaliy masalalar
Avval testni ishlang — har javobdan keyin izoh chiqadi. Keyin masalalarni shu yerning o'zida yechib, brauzerdagi haqiqiy Python bilan avtomatik tekshiring. Natijalaringiz kurs progressi sahifasida jamlanadi.
Bilimni tekshirish
Bob bo'yicha test
12 ta savol · har javobdan keyin to'g'ri yoki xatoligi va izoh ko'rsatiladi · oxirida natija foizda.
Amaliy masalalar
Kodni yozing va «Tekshirish»ni bosing (yoki Ctrl/⌘ + Enter). Kodingiz shu brauzerda saqlanib turadi.
01Z-score standartlashtirish
standardize(X) — 2D massivning har ustunini o'rtacha 0, std 1 ga keltirsin (sikllarsiz, broadcasting). Std 0 bo'lgan ustunlar 0 bo'lsin (nolga bo'lish yo'q).
02Kosinus top-k qidiruv
top_k(query, docs, k) — docs (n×d) qatorlari orasidan query (d,) ga kosinus o'xshashligi eng yuqori k ta indeksni (kamayish tartibida) va o'xshashliklarni qaytarsin: (idx, sims). Sikl ishlatmang.
03Metrikalar sikllarsiz
metrics(y_true, y_pred) — 0/1 massivlar uchun {"accuracy", "precision", "recall", "f1"} lug'atini qaytarsin (NumPy, sikllarsiz). Nolga bo'linish holatida 0.0.