Arifmetika va broadcasting: sikl yozmasdan hisoblash
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.
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)
(3, 5)
Har elementga: arifmetika va ufunc lar
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])))
[ 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):
print(narx[0] > narx[1]) print(np.maximum(narx[0], narx[1]))
[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:
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])))
[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
print(0.1 + 0.2 == 0.3) print(f"{0.1 + 0.2:.20f}") print(np.isclose(0.1 + 0.2, 0.3))
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
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)
[ 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)
narx + ustama:(3, 5) + (5,). Ustama — har mahsulot uchun bitta son. NumPy uni har qatorga (har filialga) takrorlaydi.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:
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])
(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:
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))
(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.
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()
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
nanyokiinfberadi, dastur to'xtamaydi —np.isnanbilan 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.shapeni tekshiring.
Mashqlar
narxdagi har filial narxini o'sha filialning eng arzon mahsulotiga bo'ling (maslahat:min(axis=1)va shakl).np.arange(1, 10)dan 9×9 ko'paytirish jadvalini bitta amal bilan yasang.np.array([2, 4]) / np.array([0, 0])— natija va nega?(4, 1) + (3,)ning natija shakli qanday? Avval qoidadan toping, keyin tekshiring.
Javoblar
narx / narx.min(axis=1, keepdims=True)—(3, 1)shakl har qatorga to'g'ri tushadi;keepdims5-bobda.np.arange(1, 10)[:, None] * np.arange(1, 10)—(9, 1) * (9,)→(9, 9).[inf inf]va ogohlantirish: musbat son nolga bo'linsa cheksizlik.(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.