Asosiy qismga o'tish

Arifmetika va broadcasting: sikl yozmasdan hisoblash

4-bob 9 kod bloki 1673 so'z

Sahna: narxlar jadvali

Do'konda 5 ta mahsulot, 3 ta filial. Har filial har mahsulotni o'z narxida sotadi. Bugungi topshiriqlar: hamma narxga 12% QQS qo'shing, har filialning o'z chegirmasini qo'llang, narxlarni filiallar bo'yicha solishtiring. Python bilan bu — ichma-ich ikki sikl. NumPy bilan — bitta qator.

python9 qator
import numpy as np

mahsulotlar = np.array(["non", "sut", "guruch", "yog'", "choy"])
narx = np.array([
    [5_000, 12_000, 18_000, 32_000, 25_000],
    [5_500, 11_500, 17_000, 31_000, 26_000],
    [4_800, 12_500, 18_500, 33_500, 24_000],
])
print(narx.shape)
Chiqish
(3, 5)

Har elementga: arifmetika va ufunc lar

python4 qator
qqs = narx * 1.12
print(qqs.round(0)[0])
print(narx[1], narx[1] // 1000, narx[1] % 1000)
print(np.sqrt(np.array([4, 9, 16])), np.abs(np.array([-3, 2])))
Chiqish
[ 5600. 13440. 20160. 35840. 28000.]
[ 5500 11500 17000 31000 26000] [ 5 11 17 31 26] [500 500   0   0   0]
[2. 3. 4.] [3 2]

*, +, -, /, // (butun bo'lish: 5 500 // 1 000 = 5), % (qoldiq: 500), ** (daraja) — hammasi har elementga alohida qo'llanadi. np.sqrt, np.abs, np.log, np.exp, np.round kabi funksiyalar ufunc (universal function) deyiladi: ular ham array ni "birdaniga" qayta ishlaydi, sikl C ichida.

Taqqoslash ham element-ma-element va natija — True/False massivi (3-bobdagi mask):

python2 qator
print(narx[0] > narx[1])
print(np.maximum(narx[0], narx[1]))
Chiqish
[False  True  True  True False]
[ 5500 12000 18000 32000 26000]

np.maximum ikki massivni juftma-juft solishtirib, har o'rinda kattasini oladi. np.max esa bitta massivning eng kattasini beradi — nomi o'xshash, ishi boshqa.

Nolga bo'lish: xato emas, maxsus son

Python da 1 / 0 — ZeroDivisionError, dastur to'xtaydi. NumPy da esa hisob davom etadi:

python10 qator
import warnings

sotildi = np.array([10, 0, 5])
tushum = np.array([50_000, 0, 30_000])
with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    ortacha = tushum / sotildi
    print(ortacha)
    print(np.array([1.0]) / 0)
print(np.isnan(ortacha), np.isinf(np.array([1.0, np.inf])))
Chiqish
[5000.   nan 6000.]
[inf]
[False  True False] [False  True]
  • 0 / 0 → nan (Not a Number — "aniqlanmagan").
  • 1 / 0 → inf (cheksiz).

Nega NumPy to'xtamaydi? Million qatorli hisobda bitta nol butun ishni to'xtatsa, qolgan 999 999 natija ham yo'qoladi. Shuning uchun u ogohlantirish beradi va nan/inf qo'yadi — keyin ularni np.isnan, np.isinf bilan topib, qaror qilasiz. Bitta nan keyingi har qanday yig'indini ham nan qiladi (5-bobda ko'ramiz) — shuning uchun ularni e'tiborsiz qoldirmang.

Kasr sonlar: 0.1 + 0.2 nimaga teng

python3 qator
print(0.1 + 0.2 == 0.3)
print(f"{0.1 + 0.2:.20f}")
print(np.isclose(0.1 + 0.2, 0.3))
Chiqish
False
0.30000000000000004441
True

Bu NumPy xatosi emas — kompyuter kasrlarni ikkilik sanoq sistemasida saqlaydi va 0.1 ni aniq ifodalay olmaydi (xuddi 1/3 ni o'nli kasrda aniq yozib bo'lmagani kabi). Qoida: kasr sonlarni == bilan solishtirmang, np.isclose ishlating — u "deyarli teng" ni tekshiradi.

Broadcasting: shakllar mos kelmasa

Endi asosiy savol: har xil shakldagi massivlarni qanday qo'shish mumkin?

Broadcasting: kichik shakl kattasiga xayolan cho'ziladi

Broadcasting: kichik shakl kattasiga xayolan cho'ziladi

python6 qator
ustama = np.array([0, 500, 1_000, 2_000, 1_500])
print((narx + ustama)[0])

chegirma = np.array([[0.95], [0.90], [1.00]])
print((narx * chegirma).astype(int))
print(chegirma.shape, "*", narx.shape, "->", (narx * chegirma).shape)
Chiqish
[ 5000 12500 19000 34000 26500]
[[ 4750 11400 17100 30400 23750]
 [ 4950 10350 15300 27900 23400]
 [ 4800 12500 18500 33500 24000]]
(3, 1) * (3, 5) -> (3, 5)
  1. narx + ustama: (3, 5) + (5,). Ustama — har mahsulot uchun bitta son. NumPy uni har qatorga (har filialga) takrorlaydi.
  2. narx * chegirma: (3, 5) * (3, 1). Chegirma — har filial uchun bitta son (ustun). U har ustunga takrorlanadi: birinchi filial −5%, ikkinchisi −10%, uchinchisi chegirmasiz.

Takrorlash xayoliy: NumPy ustama ni xotirada uch marta ko'chirmaydi, shunchaki hisobda qayta ishlatadi. Shuning uchun broadcasting tez va xotira tejaydi.

Qoida: shakllar o'ng tomondan solishtiriladi. Har juft o'lcham yo teng, yo biri 1 bo'lishi kerak. Aks holda — xato:

python5 qator
for chap, ong in [((3, 5), (5,)), ((3, 1), (1, 5)), ((3, 5), (3,))]:
    try:
        print(chap, "+", ong, "->", (np.ones(chap) + np.ones(ong)).shape)
    except ValueError as xato:
        print(chap, "+", ong, "-> xato:", str(xato).split("  ")[0][:55])
Chiqish
(3, 5) + (5,) -> (3, 5)
(3, 1) + (1, 5) -> (3, 5)
(3, 5) + (3,) -> xato: operands could not be broadcast together with shapes (3

(3, 5) + (3,) ishlamaydi: o'ngdan solishtirilganda 5 va 3 — teng emas, hech biri 1 emas. Filial bo'yicha qo'shmoqchi bo'lsangiz, uni ustun qilib berish kerak — (3, 1).

Jim xato: (3,) va (3, 1)

Broadcasting ning qorong'i tomoni — u xato bo'lishi kerak bo'lgan joyda ham ishlab ketadi:

python6 qator
haqiqiy = np.array([100, 200, 300])
bashorat = np.array([[110], [190], [330]])
farq = haqiqiy - bashorat
print(farq.shape)
print("noto'g'ri xato o'rtachasi:", np.abs(farq).mean().round(1))
print("to'g'ri xato o'rtachasi:  ", np.abs(haqiqiy - bashorat.ravel()).mean().round(1))
Chiqish
(3, 3)
noto'g'ri xato o'rtachasi: 98.9
to'g'ri xato o'rtachasi:   16.7

3 ta farq kutgandik, (3, 3) — 9 ta oldik, va o'rtacha ham noto'g'ri chiqdi. Hech qanday xato yo'q. Bunday narsa ML da tez-tez bo'ladi: model bashorati ko'pincha (n, 1) shaklda qaytadi, haqiqiy qiymatlar esa (n,). Himoya bitta: har hisobdan keyin shape ni tekshiring va shaklni aniq qiling (.ravel() yoki .reshape(-1) — 6-bobda).

Amaliy: ustunlarni standartlash

ML da eng ko'p ishlatiladigan broadcasting — har ustunni o'z o'rtachasi va tarqalishi bo'yicha standartlash: (x − o'rtacha) / standart og'ish. Natijada har ustun o'rtachasi 0, tarqalishi 1 bo'ladi va maydon (m²) bilan xonalar sonini bir shkalada solishtirish mumkin.

python12 qator
rng = np.random.default_rng(5)
uylar = np.column_stack([rng.normal(65, 18, 200), rng.integers(1, 6, 200)]).round(1)
z = (uylar - uylar.mean(axis=0)) / uylar.std(axis=0)
print("oldin o'rtacha:", uylar.mean(axis=0).round(2), "| keyin:", z.mean(axis=0).round(2))
print("oldin tarqalish:", uylar.std(axis=0).round(2), "| keyin:", z.std(axis=0).round(2))

fig, (chap, ong) = plt.subplots(1, 2, figsize=(10, 3.2))
chap.boxplot([uylar[:, 0], uylar[:, 1]], labels=["maydon, m²", "xonalar"])
chap.set_title("Oldin: har xil shkala")
ong.boxplot([z[:, 0], z[:, 1]], labels=["maydon (z)", "xonalar (z)"])
ong.set_title("Keyin: bir xil shkala")
plt.show()
Chiqish
oldin o'rtacha: [63.83  2.98] | keyin: [0. 0.]
oldin tarqalish: [17.32  1.42] | keyin: [1. 1.]

uylar.mean(axis=0) — har ustunning o'rtachasi, shakli (2,). (200, 2) − (2,) — broadcasting uni har qatordan ayiradi. Chapdagi rasmda maydon xonalardan ancha katta sonlarda yashaydi va xonalar deyarli ko'rinmaydi; o'ngda ikkalasi bir shkalada. scikit-learn ning StandardScaler i ichida aynan shu ikki amal.

Xulosa

  • Arifmetika va ufunc lar (np.sqrt, np.round, np.abs...) har elementga qo'llanadi; taqqoslash mask beradi.
  • np.maximum — ikki massivni juftma-juft; np.max — bitta massivning eng kattasi.
  • Nolga bo'lish nan yoki inf beradi, dastur to'xtamaydi — np.isnan bilan toping.
  • Kasr sonlar uchun == emas, np.isclose.
  • Broadcasting: o'ngdan solishtirish, o'lcham teng yoki 1; takrorlash xayoliy va tez.
  • (n,) bilan (n, 1) aralashsa — jim xato: natija (n, n) bo'lib qoladi. shape ni tekshiring.

Mashqlar

  1. narx dagi har filial narxini o'sha filialning eng arzon mahsulotiga bo'ling (maslahat: min(axis=1) va shakl).
  2. np.arange(1, 10) dan 9×9 ko'paytirish jadvalini bitta amal bilan yasang.
  3. np.array([2, 4]) / np.array([0, 0]) — natija va nega?
  4. (4, 1) + (3,) ning natija shakli qanday? Avval qoidadan toping, keyin tekshiring.

Javoblar

  1. narx / narx.min(axis=1, keepdims=True) — (3, 1) shakl har qatorga to'g'ri tushadi; keepdims 5-bobda.
  2. np.arange(1, 10)[:, None] * np.arange(1, 10) — (9, 1) * (9,) → (9, 9).
  3. [inf inf] va ogohlantirish: musbat son nolga bo'linsa cheksizlik.
  4. (4, 3): o'ngdan 1 va 3 → 3; keyin 4 va (yo'q) → 4.

Bu bobni bepul o'qidingiz.

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

Telegramda yozish Narxlar