10.2 Mátrixszorzás és lineáris transzformáció

10.2.1 Cél és konkrét helyzet

A helyzet: három rendelést választottunk ki a Northstar-példából. Minden rendeléshez két, a rendelés pillanatában ismert jellemző tartozik: a szállítási távolság kilométerben (distance_km) és a kosárérték eurócentben (basket_minor). Egy kolléga adott nekünk egy kézi, még nem tanított lineáris modellt a várható kézbesítési napokra:

ŷi=2.0+0.3⋅distance_kmi+0.0002⋅basket_minori. \hat y_i \;=\; 2.0 \;+\; 0.3 \cdot \text{distance\_km}_i \;+\; 0.0002 \cdot \text{basket\_minor}_i .

A három megfigyelési egység egy-egy rendelés:

Rendelés distance_km basket_minor
R01 10 2500
R02 25 5000
R03 5 1000

Cél: ezt a három predikciót egyszerre, mátrixműveletként kiszámítani, és elkülöníteni a mátrixszorzást a koordinátánkénti szorzástól. A fejezetben nem becslünk súlyokat; a súlyokat adottnak vesszük. A súlyok becslése a következő alfejezet (Vetítés és legkisebb négyzetek) feladata lesz.

Előzetes becslés a téma előtt: számold ki kézzel az első rendelés predikcióját: 2.0+0.3⋅10+0.0002⋅25002.0 + 0.3 \cdot 10 + 0.0002 \cdot 2500. Ha 5.55.5 nap jött ki, jó úton jársz; a mátrixszorzás pontosan ezt a műveletet végzi el egyszerre minden sorra.

10.2.2 Fogalmi magyarázat: a mátrixszorzás mint sor-skaláris szorzat

10.2.2.1 Kétismeretlenes egyenletből mátrixszorzáshoz

Induljunk ki egy közismert lineáris egyenletrendszerből:

{2a+3b=13,4a+b=11. \begin{cases} 2a + 3b = 13, \\ 4a + \; b = 11. \end{cases}

Ezt úgy írhatjuk tömören, hogy az együtthatókat egy 2×22 \times 2-es mátrixba gyűjtjük, az ismeretleneket pedig oszlopvektorba:

𝐀=(2341),𝐳=(ab),𝐀𝐳=(2a+3b4a+b)=(1311). \mathbf A = \begin{pmatrix} 2 & 3 \\ 4 & 1 \end{pmatrix}, \qquad \mathbf z = \begin{pmatrix} a \\ b \end{pmatrix}, \qquad \mathbf A \mathbf z = \begin{pmatrix} 2a + 3b \\ 4a + b \end{pmatrix} = \begin{pmatrix} 13 \\ 11 \end{pmatrix}.

A mátrixszorzás (matrix product) szabálya tehát: a kimenet ii-edik eleme az 𝐀\mathbf A ii-edik sora és a 𝐳\mathbf z oszlopa skaláris szorzata. A skaláris szorzatot az előző alfejezetben, Vektor, skalárszorzat, norma és távolság alfejezetben definiáltuk: koordinátaszorzatok összege. A példa megoldása a=2a=2, b=3b=3, mert 2⋅2+3⋅3=132\cdot 2+3\cdot 3=13 és 4⋅2+1⋅3=114\cdot 2+1\cdot 3=11.

10.2.2.2 A design mátrix és az XwXw predikció

A predikciós feladatban az 𝐀\mathbf A szerepét a design mátrix (design matrix) veszi át, jele 𝐗\mathbf X. Egy 𝐗\mathbf X mátrix n×pn \times p alakú, ha nn megfigyelés és pp oszlop van. Minden sor egy megfigyelés, minden oszlop egy jellemző. A fenti három rendelésnél n=3n=3; ha a tengelymetszethez (intercept) tartozó, csupa 11-es oszlopot is hozzáadjuk, akkor p=3p=3:

𝐗=(11025001255000151000),𝐰=(w0w1w2)=(2.00.30.0002). \mathbf X = \begin{pmatrix} 1 & 10 & 2500 \\ 1 & 25 & 5000 \\ 1 & 5 & 1000 \end{pmatrix}, \qquad \mathbf w = \begin{pmatrix} w_0 \\ w_1 \\ w_2 \end{pmatrix} = \begin{pmatrix} 2.0 \\ 0.3 \\ 0.0002 \end{pmatrix}.

A lineáris predikció:

𝐲̂=𝐗𝐰. \hat{\mathbf y} = \mathbf X \mathbf w .

Ebben a példában:

𝐲̂=(1⋅2.0+10⋅0.3+2500⋅0.00021⋅2.0+25⋅0.3+5000⋅0.00021⋅2.0+5⋅0.3+1000⋅0.0002)=(5.510.53.7). \hat{\mathbf y} = \begin{pmatrix} 1 \cdot 2.0 + 10 \cdot 0.3 + 2500 \cdot 0.0002 \\ 1 \cdot 2.0 + 25 \cdot 0.3 + 5000 \cdot 0.0002 \\ 1 \cdot 2.0 + 5 \cdot 0.3 + 1000 \cdot 0.0002 \end{pmatrix} = \begin{pmatrix} 5.5 \\ 10.5 \\ 3.7 \end{pmatrix}.

10.2.2.3 Alakok és mértékegységek

A mátrixszorzás alakszabálya: ha 𝐗\mathbf X alakja (n,p)(n, p) és 𝐰\mathbf w alakja (p,1)(p, 1), akkor 𝐲̂\hat{\mathbf y} alakja (n,1)(n, 1). A két belső dimenzió, pp, megegyezik, és a szorzás során eltűnik. Szavakkal: annyi kimenet lesz, ahány sor, és minden kimenet annyi tagot összegez, ahány oszlop.

A súlyok mértékegysége a predikciót teszi dimenzionálisan helyessé. Ha a cél a kézbesítési napok száma, akkor:

A súlyok tehát nem puszta számok: átváltják a jellemző mértékegységét a cél mértékegységére. A szorzatok azért összeadhatók, mert mindegyik tag már nap egységben van.

10.2.2.4 Transzponálás és a sor-oszlop átrendezés

A transzponált (transpose) mátrix sorait és oszlopait felcseréli:

(𝐗T)ij=𝐗ji. \big(\mathbf X^T\big)_{ij} = \mathbf X_{ji}.

Ha 𝐗\mathbf X alakja (n,p)(n, p), akkor 𝐗T\mathbf X^T alakja (p,n)(p, n). A fenti példában:

𝐗T=(11110255250050001000). \mathbf X^T = \begin{pmatrix} 1 & 1 & 1 \\ 10 & 25 & 5 \\ 2500 & 5000 & 1000 \end{pmatrix}.

A transzponálás a becslés későbbi lépésében, az 𝐗T𝐗\mathbf X^T \mathbf X mátrixban tér majd vissza; egyelőre elég annyi, hogy a sorok és oszlopok megcserélésével a „minta” és a „jellemző” irány felcserélhető.

10.2.2.5 Bázis és tengelymetszet

A design mátrix oszlopai tekinthetők bázisfüggvény-vektoroknak (basis vectors). A predikció az oszlopok lineáris kombinációja:

𝐲̂=w0(111)⏟intercept oszlop+w1(10255)⏟távolság oszlop+w2(250050001000)⏟kosárérték oszlop. \hat{\mathbf y} = w_0 \underbrace{\begin{pmatrix}1\\1\\1\end{pmatrix}}_{\text{intercept oszlop}} + w_1 \underbrace{\begin{pmatrix}10\\25\\5\end{pmatrix}}_{\text{távolság oszlop}} + w_2 \underbrace{\begin{pmatrix}2500\\5000\\1000\end{pmatrix}}_{\text{kosárérték oszlop}}.

A csupa 11-es oszlop az intercept oszlop; a hozzá tartozó w0w_0 a tengelymetszet, vagyis az a predikció, amikor minden numerikus jellemző nulla. A „bázis” itt annyit jelent: a modell által elérhető predikciók az oszlopvektorok összes lehetséges lineáris kombinációja. Ez a kép lesz fontos a legkisebb négyzeteknél (Vetítés és legkisebb négyzetek) és a főkomponens-elemzésnél (PCA: skála, vetítés és megőrzött variancia).

10.2.2.6 Miért nem koordinátánkénti szorzás?

A NumPy-ban és sok más eszközben két művelet hasonlít egymásra:

A predikció nem elemenkénti szorzás, mert 𝐗\mathbf X alakja (3,3)(3,3), a súlyok alakja pedig (3,)(3,), tehát nincs sor-sor pár. A helyes művelet a mátrixszorzás: minden sor a teljes súlyvektorral kombinálódik. A koordinátánkénti szorzás csak közbülső lépés lehet, de önmagában nem adja a predikciót.

10.2.3 Teljes minimális munkapélda

A labor konkrét célja: három mintára, két valódi jellemzővel számítsuk ki a lineáris predikciót először kézzel, majd a NumPy @ operátorával. A kézi számítást már elvégeztük fent; az eredmény [5.5,10.5,3.7][5.5, 10.5, 3.7].

import numpy as np

# Minden sor egy rendelés.
# Az első oszlop az intercept, a második a distance_km,
# a harmadik a basket_minor.
X = np.array([
    [1.0, 10.0, 2500.0],
    [1.0, 25.0, 5000.0],
    [1.0,  5.0, 1000.0],
])

# Súlyok: w0 = 2 nap, w1 = 0.3 nap/km, w2 = 0.0002 nap/eurocent.
w = np.array([2.0, 0.3, 0.0002])

# Mátrixszorzás: (3, 3) @ (3,) -> (3,)
y_hat = X @ w

# Kézi ellenőrzés oszloponkénti súlyozott összeggel.
manual = X[:, 0] * w[0] + X[:, 1] * w[1] + X[:, 2] * w[2]

print("X.shape:", X.shape)        # (3, 3)
print("w.shape:", w.shape)        # (3,)
print("y_hat.shape:", y_hat.shape)  # (3,)
print("y_hat:", y_hat)            # várhatóan [5.5 10.5 3.7]
print("allclose:", np.allclose(y_hat, manual, rtol=1e-12, atol=1e-12))

Szemléltető kimenet, nem mért futtatás; a kézi kontroll alapján várható:

X.shape: (3, 3)
w.shape: (3,)
y_hat.shape: (3,)
y_hat: [ 5.5 10.5  3.7]
allclose: True

A manual sor azt mutatja, hogy a mátrixszorzás belül oszloponkénti elemenkénti szorzások összege, de maga az X * w kifejezés nem a predikció. Ezt a megkülönböztetést a gyakori tévedéseknél részletezzük.

10.2.4 Az eredmény értelmezése

A három predikció: 5.55.5, 10.510.5, 3.73.7 nap. Az első rendelésre a kézi számítás pontosan ezt adta, tehát a kód alakja és iránya jó. A kimenet shape=(3,), dtype=float64, mert a bemenetek float64 mátrixok. A np.allclose azért hasznos, mert a 0.3 és 0.0002 bináris ábrázolása nem mindig egzakt; rtol=1e-12, atol=1e-12 toleranciával a gépi és kézi eredmény megegyezik.

Értelmezési korlát: ez a lineáris modell additív és globálisan lineáris. Ha a távolság 00 és a kosárérték 00, a predikció 22 nap; ha a távolság nagyon nagy, a predikció tetszőlegesen nagy lehet. A valós kézbesítés nem lehet negatív és nem nőhet minden határon túl; a későbbi modellezésnél nemlineáris vagy korlátos modellt választunk. A log-skálát Exponenciális és logaritmikus skála alfejezetben láttuk: ha a cél logy\log y lenne, a súlyok multiplikatív hatást jelentenének a nyers skálán. Itt azonban nyers skálán dolgozunk, ezért a hozzájárulások összeadódnak.

Rövid pandas-visszautalás (Kiválasztás és módosítás Copy-on-Write mellett): ha a mátrixot egy DataFrame-ből készítjük a .to_numpy() hívással, a mátrix elveszíti a sorindexet. A predikció visszaírásánál ezért mindig a DataFrame eredeti indexét használjuk, ne a NumPy pozícióját. A példában a sorrend és az index azonos, de nagyobb táblánál ez a leggyakoribb csendes hiba.

10.2.5 Feladatok

  1. Értelmezés. Adott egy másik kézi súlyvektor: w0=1.0w_0=1.0 nap, w1=0.2w_1=0.2 nap/km, w2=0.0005w_2=0.0005 nap/eurocent. Számold ki kézzel a predikciót arra a két új rendelésre, ahol (distance_km, basket_minor) rendre (20,4000)(20, 4000) és (8,1200)(8, 1200). Mi a mértékegysége w1w_1 és w2w_2 fontos szerepének?

  2. Megvalósítás. Építsd meg 𝐗\mathbf X-et a fenti három rendelés adatával, de a súlyokat most válaszd w0=1.8w_0=1.8, w1=0.22w_1=0.22, w2=0.00035w_2=0.00035 értékűre. Számold ki 𝐗𝐰\mathbf X \mathbf w értékét a @ operátorral, és ellenőrizd az első sorra kézi számítással. Ellenőrizd a shape értékét is.

  3. Hibakeresés. Egy kolléga ezt írta ugyanarra az 𝐗\mathbf X-re, w=(2.0,0.3,0.0002)w=(2.0,\,0.3,\,0.0002) súlyokkal:

    pred = X * w

    Mi ez pontosan? Miért nem a lineáris predikció? Add meg, mit kap a kolléga az első sorban, és javítsd a kódot két módon: @ operátorral, illetve az elemenkénti szorzat explicit sorösszegzésével.

  4. Megváltozott feltétel / továbbvitel. Adj a modellhez egy harmadik jellemzőt: quantity_sum, az adott rendelés összes darabszámát. A három rendelésre legyen (4,6,7)(4, 6, 7), az új súly pedig w3=0.1w_3=0.1 nap/darab. Írd fel az új 𝐗\mathbf X mátrixot, add meg az alakját, és számold ki az új predikciókat @ operátorral. Ellenőrizd kézzel az R01 rendelés predikcióját.

  5. Értelmezés: mátrixszorzás és nem kommutativitás. Legyen

    𝐀=(2341),𝐁=(1021). \mathbf A = \begin{pmatrix} 2 & 3 \\ 4 & 1 \end{pmatrix}, \quad \mathbf B = \begin{pmatrix} 1 & 0 \\ 2 & 1 \end{pmatrix}.

    Számold ki kézzel 𝐀𝐁\mathbf A \mathbf B-t és 𝐁𝐀\mathbf B \mathbf A-t. Milyen alakú a két eredmény? Mit jelent ez a „mátrixosztás” szempontjából?

10.2.6 Megoldások és indoklás

1. megoldás. A predikció:

ŷ=1.0+0.2⋅distance+0.0005⋅basket. \hat y = 1.0 + 0.2 \cdot \text{distance} + 0.0005 \cdot \text{basket}.

A w1w_1 mértékegysége nap/km, mert a km-t napra váltja; a w2w_2 mértékegysége nap/eurocent. A mértékegységek nélkül a 4.04.0 és 2.02.0 tagot nem lehetne egy nap-skálán összeadni.

2. megoldás.

import numpy as np

X = np.array([
    [1.0, 10.0, 2500.0],
    [1.0, 25.0, 5000.0],
    [1.0,  5.0, 1000.0],
])
w = np.array([1.8, 0.22, 0.00035])

y_hat = X @ w
print("shape:", y_hat.shape)
print("y_hat:", y_hat)

Várható kimenet: shape: (3,), y_hat: [4.875 8.05 3.25].

Ellenőrzés az első sorra:

1.8+0.22⋅10+0.00035⋅2500=1.8+2.2+0.875=4.875. 1.8 + 0.22 \cdot 10 + 0.00035 \cdot 2500 = 1.8 + 2.2 + 0.875 = 4.875 .

3. megoldás. A X * w kifejezés NumPy-ban elemenkénti szorzás broadcastinggal. Mivel 𝐗\mathbf X alakja (3,3)(3,3) és 𝐰\mathbf w alakja (3,)(3,), a 𝐰\mathbf w az utolsó tengelyre illeszkedik, ezért a kolléga eredménye:

𝐗*𝐰=(1⋅2.010⋅0.32500⋅0.00021⋅2.025⋅0.35000⋅0.00021⋅2.05⋅0.31000⋅0.0002)=(2.03.00.52.07.51.02.01.50.2). \mathbf X * \mathbf w = \begin{pmatrix} 1 \cdot 2.0 & 10 \cdot 0.3 & 2500 \cdot 0.0002 \\ 1 \cdot 2.0 & 25 \cdot 0.3 & 5000 \cdot 0.0002 \\ 1 \cdot 2.0 & 5 \cdot 0.3 & 1000 \cdot 0.0002 \end{pmatrix} = \begin{pmatrix} 2.0 & 3.0 & 0.5 \\ 2.0 & 7.5 & 1.0 \\ 2.0 & 1.5 & 0.2 \end{pmatrix}.

Ez nem a predikció, hanem egy (3,3)(3,3)-as mátrix. Az első sor helyes predikciója 2.0+3.0+0.5=5.52.0+3.0+0.5=5.5, tehát a kolléga csak akkor kapná meg a predikciókat, ha utána soronként összegezné, például:

pred = (X * w).sum(axis=1)

Ez azonban véletlenül működik az egydimenziós 𝐰\mathbf w esetben; ha 𝐰\mathbf w oszlopvektor, az elemenkénti szorzás egészen mást ad. A helyes, szándékot tükröző megoldás a mátrixszorzás:

pred = X @ w

A javítási elv: mindig a dimenziókból indulj ki, és a predikciót 𝐗𝐰\mathbf X\mathbf w-ként írd le. Az elemenkénti szorzás nem „rossz”, hanem más művelet.

4. megoldás. Az új design mátrix 3 sor és 4 oszlop:

𝐗new=(11025004125500061510007),𝐰new=(2.00.30.00020.1). \mathbf X_{\text{new}} = \begin{pmatrix} 1 & 10 & 2500 & 4 \\ 1 & 25 & 5000 & 6 \\ 1 & 5 & 1000 & 7 \end{pmatrix}, \qquad \mathbf w_{\text{new}} = \begin{pmatrix} 2.0 \\ 0.3 \\ 0.0002 \\ 0.1 \end{pmatrix}.

Kódban:

X_new = np.array([
    [1.0, 10.0, 2500.0, 4.0],
    [1.0, 25.0, 5000.0, 6.0],
    [1.0,  5.0, 1000.0, 7.0],
])
w_new = np.array([2.0, 0.3, 0.0002, 0.1])

y_hat_new = X_new @ w_new
print("X_new.shape:", X_new.shape)  # (3, 4)
print("y_hat_new:", y_hat_new)      # [5.9 11.1  4.4]

Kézi ellenőrzés R01-re: 2.0+0.3⋅10+0.0002⋅2500+0.1⋅4=2.0+3.0+0.5+0.4=5.92.0 + 0.3\cdot 10 + 0.0002\cdot 2500 + 0.1\cdot 4 = 2.0 + 3.0 + 0.5 + 0.4 = 5.9 nap. A X_new.shape (3,4)(3,4), mert az intercept és a három jellemző négy oszlopot ad.

5. megoldás. A szorzás:

𝐀𝐁=(2⋅1+3⋅22⋅0+3⋅14⋅1+1⋅24⋅0+1⋅1)=(8361). \mathbf A \mathbf B = \begin{pmatrix} 2\cdot 1 + 3\cdot 2 & 2\cdot 0 + 3\cdot 1 \\ 4\cdot 1 + 1\cdot 2 & 4\cdot 0 + 1\cdot 1 \end{pmatrix} = \begin{pmatrix} 8 & 3 \\ 6 & 1 \end{pmatrix}.

𝐁𝐀=(1⋅2+0⋅41⋅3+0⋅12⋅2+1⋅42⋅3+1⋅1)=(2387). \mathbf B \mathbf A = \begin{pmatrix} 1\cdot 2 + 0\cdot 4 & 1\cdot 3 + 0\cdot 1 \\ 2\cdot 2 + 1\cdot 4 & 2\cdot 3 + 1\cdot 1 \end{pmatrix} = \begin{pmatrix} 2 & 3 \\ 8 & 7 \end{pmatrix}.

A két eredmény különböző, tehát a mátrixszorzás nem kommutatív. Ezért nincs értelmes „mátrixosztás” úgy, ahogy a valós számoknál b/ab/a működik. Ha egy 𝐀𝐳=𝐛\mathbf A\mathbf z=\mathbf b egyenletet akarunk megoldani, külön műveletet használunk: 𝐳=𝐀−1𝐛\mathbf z=\mathbf A^{-1}\mathbf b vagy numerikusan jobb 𝐳=solve(𝐀,𝐛)\mathbf z=\text{solve}(\mathbf A,\mathbf b). A design mátrix predikciója viszont nem old meg egyenletet: ott 𝐰\mathbf w adott, és 𝐲̂=𝐗𝐰\hat{\mathbf y}=\mathbf X\mathbf w kiszámítása szorzás.

10.2.7 Gyakori tévedés és ellenpélda

Az invertálás, az elemenkénti osztás és a lineáris rendszer megoldása külön művelet.

Tegyük fel, hogy valaki meg akarja oldani a fenti 𝐀𝐳=𝐛\mathbf A\mathbf z=\mathbf b rendszert 𝐀=(2341)\mathbf A=\begin{pmatrix}2&3\\4&1\end{pmatrix} és 𝐛=(1311)\mathbf b=\begin{pmatrix}13\\11\end{pmatrix} esetén. Három gyakori, de eltérő jelentésű kifejezés:

  1. Elemenkénti osztás: b / A Python/NumPy-ban nem mátrixosztás. Ha egyáltalán lefut, a / elemenként oszt, és az alakokat a broadcasting szabályai szerint illeszti. A fenti 𝐛\mathbf b alakja (2,)(2,), 𝐀\mathbf A alakja (2,2)(2,2); ez leggyakrabban ValueError. Ha mégis lefutna, akkor is elemenkénti hányadosokat adna, nem az egyenletrendszer megoldását.

  2. Invertálás: np.linalg.inv(A) @ b matematikailag helyes, ha 𝐀\mathbf A invertálható. Numerikusan azonban rossz szokás, mert az inverz kiszámítása instabil lehet. Az ajánlott megoldás:

    z = np.linalg.solve(A, b)   # z = [2.0, 3.0]
  3. Predikció: X @ w. Itt 𝐗\mathbf X általában nem négyzetes; ha n≠pn \ne p, nem is beszélhetünk egyértelmű inverzről. A cél pedig nem megoldani egy egyenletet, hanem a súlyokkal kiszámítani a predikciót.

A koordinátánkénti szorzás csendes csapdája. A fenti X * w példa mutatja, hogy a broadcasting miatt a rossz művelet is lefuthat. Ellenőrzésképpen soha ne csak a kódot futtasd, hanem egy sorra kézzel is számold ki a várt eredményt. A mátrixszorzás alakszabálya a belső dimenzió egyezése: (n,p)@(p,)→(n,)(n,p) @ (p,) \to (n,). Ha ezt a dimenziót nem ellenőrizzük, a broadcasting kiszámítható, de értelmetlen eredményt adhat.

10.2.8 Önellenőrzés

  1. Adott 𝐗\mathbf X alakja (100,8)(100, 8) és 𝐰\mathbf w alakja (8,)(8,). Mi a predikció alakja, és hány tagot összegez minden sor?
    <details><summary>Válasz</summary>A predikció alakja (100,)(100,); minden sor 8 tagot (intercept + 7 jellemző, ha az első oszlop intercept) összegez.</details>

  2. Miért kell az interceptet külön 11-es oszlopként felvenni?
    <details><summary>Válasz</summary>Mert a mátrixszorzás minden kimenetet ∑jXijwj\sum_j X_{ij}w_j alakban állít elő. Az 11-es bejegyzés révén jelenik meg a w0w_0 tag, amely így nem függ egyetlen jellemzőtől sem.</details>

  3. Milyen műveletek a * és a @ NumPy-ban?
    <details><summary>Válasz</summary>A * elemenkénti (Hadamard-) szorzás broadcastinggal; a @ mátrixszorzás, sor-oszlop skaláris szorzatokkal.</details>

  4. Mi az alakszabálya 𝐗T𝐗\mathbf X^T \mathbf X szorzatnak, ha 𝐗\mathbf X alakja (n,p)(n,p)?
    <details><summary>Válasz</summary>𝐗T\mathbf X^T alakja (p,n)(p,n), így a szorzat (p,p)(p,p); ez lesz a normálegyenlet mátrixa a következő alfejezetben.</details>

A NumPy * operátora elemenkénti szorzást végez, míg a @ mátrixszorzást. A vektor- és mátrixdimenziókat ellenőrizzük, mert a nem szándékolt broadcasting numerikusan lefuthat úgy is, hogy hibás eredményt ad.

10.2.9 Rövid összefoglaló

A mátrixszorzás a lineáris predikció alapművelete: az n×pn \times p design mátrix minden sorát ugyanazzal a pp hosszú súlyvektorral kombinálja skaláris szorzatként, így 𝐲̂=𝐗𝐰\hat{\mathbf y}=\mathbf X\mathbf w egyszerre adja meg minden megfigyelés predikcióját. A design mátrix sora egy megfigyelés, oszlopa egy jellemző; az interceptet csupa 11-es oszlop képviseli. A transzponálás sor és oszlop felcserélése, a bázisok a mátrix oszlopvektorainak lineáris kombinációi. A NumPy @ operátora mátrixszorzás, a * elemenkénti szorzás; a kettő nem felcserélhető. A következő alfejezetben ezt a műveletet használjuk a vetítéshez és a legkisebb négyzetes becsléshez, ahol 𝐗T𝐗\mathbf X^T\mathbf X és 𝐗T𝐲\mathbf X^T\mathbf y jelenik meg.