TipCo se naučíte

V této kapitole se naučíte:

  • Chápat matice jako transformace
  • Základní transformace: rotace, škálování, zrcadlení
  • Jak skládat transformace
  • Vizualizovat efekt matic

11.1 Matice jako transformace

Každá matice reprezentuje transformaci – přeměnu jednoho vektoru na jiný. Když vynásobíme vektor maticí, “transformujeme” ho.

\[\mathbf{y} = \mathbf{A}\mathbf{x}\]

Vstup \(\mathbf{x}\) se změní na výstup \(\mathbf{y}\).

import numpy as np
import matplotlib.pyplot as plt

# Transformační matice
A = np.array([
    [2, 0],
    [0, 1]
])

# Vstupní vektor
x = np.array([1, 1])

# Transformovaný vektor
y = A @ x

print(f"Vstup x: {x}")
print(f"Matice A:\n{A}")
print(f"Výstup y = Ax: {y}")
Vstup x: [1 1]
Matice A:
[[2 0]
 [0 1]]
Výstup y = Ax: [2 1]
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Původní vektor
axes[0].annotate('', xy=x, xytext=(0, 0),
                arrowprops=dict(arrowstyle='->', color='blue', lw=2))
axes[0].plot(*x, 'bo', markersize=10)
axes[0].text(x[0]+0.1, x[1]+0.1, f'x = {list(x)}', fontsize=11, color='blue')
axes[0].set_xlim(-0.5, 3)
axes[0].set_ylim(-0.5, 2)
axes[0].set_aspect('equal')
axes[0].grid(True, alpha=0.3)
axes[0].axhline(y=0, color='k', linewidth=0.5)
axes[0].axvline(x=0, color='k', linewidth=0.5)
axes[0].set_title('Před transformací')

# Transformovaný vektor
axes[1].annotate('', xy=x, xytext=(0, 0),
                arrowprops=dict(arrowstyle='->', color='lightblue', lw=2, linestyle='--'))
axes[1].annotate('', xy=y, xytext=(0, 0),
                arrowprops=dict(arrowstyle='->', color='red', lw=2))
axes[1].plot(*y, 'ro', markersize=10)
axes[1].text(y[0]+0.1, y[1]+0.1, f'y = Ax = {list(y)}', fontsize=11, color='red')
axes[1].set_xlim(-0.5, 3)
axes[1].set_ylim(-0.5, 2)
axes[1].set_aspect('equal')
axes[1].grid(True, alpha=0.3)
axes[1].axhline(y=0, color='k', linewidth=0.5)
axes[1].axvline(x=0, color='k', linewidth=0.5)
axes[1].set_title('Po transformaci maticí A (roztažení v x)')

plt.tight_layout()
plt.show()

Matice jako transformace

11.2 Základní transformace

11.2.1 Škálování

Škálování mění velikost vektoru v jednotlivých osách:

\[\mathbf{S} = \begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix}\]

Kód
import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

# Původní čtverec
original = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).T

skalovani = [
    (np.array([[2, 0], [0, 1]]), "Roztažení v x (2×)"),
    (np.array([[1, 0], [0, 2]]), "Roztažení v y (2×)"),
    (np.array([[0.5, 0], [0, 0.5]]), "Zmenšení (0.5×)")
]

for ax, (S, title) in zip(axes, skalovani):
    transformed = S @ original

    ax.fill(original[0], original[1], alpha=0.3, color='blue', label='Původní')
    ax.fill(transformed[0], transformed[1], alpha=0.3, color='red', label='Po transformaci')
    ax.plot(original[0], original[1], 'b-', linewidth=2)
    ax.plot(transformed[0], transformed[1], 'r-', linewidth=2)

    ax.set_xlim(-0.5, 2.5)
    ax.set_ylim(-0.5, 2.5)
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3)
    ax.legend()
    ax.set_title(title)

plt.tight_layout()
plt.show()

Škálování

11.2.2 Rotace

Rotace otáčí vektor o úhel \(\theta\):

\[\mathbf{R}(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\]

import numpy as np

def rotacni_matice(uhel_stupne):
    """Vytvoří rotační matici pro daný úhel ve stupních."""
    theta = np.radians(uhel_stupne)
    return np.array([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)]
    ])

# Rotace o 45°
R45 = rotacni_matice(45)
print("Rotační matice pro 45°:")
print(R45.round(3))

# Aplikace na vektor
v = np.array([1, 0])
v_rotovany = R45 @ v
print(f"\nVektor [1, 0] po rotaci o 45°: {v_rotovany.round(3)}")
Rotační matice pro 45°:
[[ 0.707 -0.707]
 [ 0.707  0.707]]

Vektor [1, 0] po rotaci o 45°: [0.707 0.707]
import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 8))

# Původní vektor
v = np.array([1, 0])
ax.annotate('', xy=v, xytext=(0, 0),
            arrowprops=dict(arrowstyle='->', color='blue', lw=3))
ax.text(v[0]+0.1, v[1]+0.1, 'Původní (0°)', color='blue', fontsize=10)

# Rotace o různé úhly
uhly = [30, 60, 90, 120, 180]
barvy = plt.cm.rainbow(np.linspace(0, 1, len(uhly)))

for uhel, barva in zip(uhly, barvy):
    R = rotacni_matice(uhel)
    v_rot = R @ v
    ax.annotate('', xy=v_rot, xytext=(0, 0),
                arrowprops=dict(arrowstyle='->', color=barva, lw=2))
    ax.text(v_rot[0]*1.1, v_rot[1]*1.1, f'{uhel}°', fontsize=10, color=barva)

# Jednotková kružnice
theta = np.linspace(0, 2*np.pi, 100)
ax.plot(np.cos(theta), np.sin(theta), 'gray', linestyle='--', alpha=0.5)

ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
ax.axhline(y=0, color='k', linewidth=0.5)
ax.axvline(x=0, color='k', linewidth=0.5)
ax.set_title('Rotace vektoru o různé úhly')
plt.show()

Rotace o různé úhly

11.2.3 Zrcadlení

Zrcadlení převrací body přes osu:

# Zrcadlení přes osu x
import numpy as np

Mx = np.array([[1, 0], [0, -1]])

# Zrcadlení přes osu y
My = np.array([[-1, 0], [0, 1]])

# Zrcadlení přes počátek
Mo = np.array([[-1, 0], [0, -1]])

print("Zrcadlení přes osu x (y → -y):")
print(Mx)
print("\nZrcadlení přes osu y (x → -x):")
print(My)
Zrcadlení přes osu x (y → -y):
[[ 1  0]
 [ 0 -1]]

Zrcadlení přes osu y (x → -x):
[[-1  0]
 [ 0  1]]
import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

# Původní trojúhelník
original = np.array([[0, 0], [2, 0], [1, 1.5], [0, 0]]).T

zrcadleni = [
    (np.array([[1, 0], [0, -1]]), "Zrcadlení přes osu x"),
    (np.array([[-1, 0], [0, 1]]), "Zrcadlení přes osu y"),
    (np.array([[-1, 0], [0, -1]]), "Zrcadlení přes počátek")
]

for ax, (M, title) in zip(axes, zrcadleni):
    transformed = M @ original

    ax.fill(original[0], original[1], alpha=0.3, color='blue', label='Původní')
    ax.fill(transformed[0], transformed[1], alpha=0.3, color='red', label='Zrcadlený')
    ax.plot(original[0], original[1], 'b-', linewidth=2)
    ax.plot(transformed[0], transformed[1], 'r-', linewidth=2)

    ax.set_xlim(-3, 3)
    ax.set_ylim(-2, 2)
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3)
    ax.axhline(y=0, color='k', linewidth=1)
    ax.axvline(x=0, color='k', linewidth=1)
    ax.legend(loc='upper right')
    ax.set_title(title)

plt.tight_layout()
plt.show()

Zrcadlení

11.2.4 Zkosení (shear)

Zkosení posunuje body v jednom směru proporcionálně k jejich pozici v druhém:

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

original = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).T

# Zkosení v x
Shx = np.array([[1, 0.5], [0, 1]])
trans_x = Shx @ original

axes[0].fill(original[0], original[1], alpha=0.3, color='blue', label='Původní')
axes[0].fill(trans_x[0], trans_x[1], alpha=0.3, color='red', label='Po zkosení')
axes[0].set_title('Zkosení v x-směru')
axes[0].legend()
axes[0].set_aspect('equal')
axes[0].grid(True, alpha=0.3)
axes[0].set_xlim(-0.5, 2)
axes[0].set_ylim(-0.5, 1.5)

# Zkosení v y
Shy = np.array([[1, 0], [0.5, 1]])
trans_y = Shy @ original

axes[1].fill(original[0], original[1], alpha=0.3, color='blue', label='Původní')
axes[1].fill(trans_y[0], trans_y[1], alpha=0.3, color='red', label='Po zkosení')
axes[1].set_title('Zkosení v y-směru')
axes[1].legend()
axes[1].set_aspect('equal')
axes[1].grid(True, alpha=0.3)
axes[1].set_xlim(-0.5, 1.5)
axes[1].set_ylim(-0.5, 2)

plt.tight_layout()
plt.show()

Zkosení

11.3 Skládání transformací

Transformace můžeme skládat násobením matic. Pořadí je důležité!

\[\mathbf{C} = \mathbf{B} \cdot \mathbf{A}\]

Nejprve se aplikuje \(\mathbf{A}\), pak \(\mathbf{B}\).

# Rotace o 45° + škálování 2×
import numpy as np
import matplotlib.pyplot as plt

R = rotacni_matice(45)
S = np.array([[2, 0], [0, 2]])

# Složená transformace
C = S @ R  # Nejprve rotace, pak škálování

original = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).T

fig, axes = plt.subplots(1, 4, figsize=(16, 4))

# Původní
axes[0].fill(original[0], original[1], alpha=0.3, color='blue')
axes[0].set_title('1. Původní')

# Po rotaci
rotated = R @ original
axes[1].fill(original[0], original[1], alpha=0.2, color='blue')
axes[1].fill(rotated[0], rotated[1], alpha=0.3, color='green')
axes[1].set_title('2. Po rotaci (45°)')

# Po škálování
scaled = S @ rotated
axes[2].fill(rotated[0], rotated[1], alpha=0.2, color='green')
axes[2].fill(scaled[0], scaled[1], alpha=0.3, color='red')
axes[2].set_title('3. Po škálování (2×)')

# Složená transformace najednou
combined = C @ original
axes[3].fill(original[0], original[1], alpha=0.2, color='blue')
axes[3].fill(combined[0], combined[1], alpha=0.3, color='purple')
axes[3].set_title('Složená: S @ R')

for ax in axes:
    ax.set_xlim(-3, 3)
    ax.set_ylim(-3, 3)
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3)
    ax.axhline(y=0, color='k', linewidth=0.5)
    ax.axvline(x=0, color='k', linewidth=0.5)

plt.tight_layout()
plt.show()

Skládání transformací
VarováníPořadí záleží!

Rotace + škálování ≠ Škálování + rotace

import numpy as np
import matplotlib.pyplot as plt

R = rotacni_matice(45)
S = np.array([[2, 0], [0, 1]])  # Nerovnoměrné škálování

original = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).T

# Různé pořadí
SR = S @ R  # Nejprve rotace, pak škálování
RS = R @ S  # Nejprve škálování, pak rotace

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

axes[0].fill(original[0], original[1], alpha=0.5, color='blue')
axes[0].set_title('Původní')

trans1 = SR @ original
axes[1].fill(original[0], original[1], alpha=0.2, color='blue')
axes[1].fill(trans1[0], trans1[1], alpha=0.5, color='red')
axes[1].set_title('Rotace → Škálování (S @ R)')

trans2 = RS @ original
axes[2].fill(original[0], original[1], alpha=0.2, color='blue')
axes[2].fill(trans2[0], trans2[1], alpha=0.5, color='green')
axes[2].set_title('Škálování → Rotace (R @ S)')

for ax in axes:
    ax.set_xlim(-2, 3)
    ax.set_ylim(-2, 2)
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Pořadí transformací záleží

11.4 Vizualizace efektu matice

Užitečný způsob, jak pochopit matici, je vidět, co dělá s mřížkou:

import numpy as np
import matplotlib.pyplot as plt

def vizualizuj_transformaci(A, title="Transformace"):
    """Vizualizuje efekt matice na mřížce."""
    fig, axes = plt.subplots(1, 2, figsize=(12, 5))

    # Původní mřížka
    for i in np.linspace(-2, 2, 9):
        axes[0].axhline(y=i, color='blue', alpha=0.3)
        axes[0].axvline(x=i, color='blue', alpha=0.3)

    # Jednotkové vektory
    axes[0].annotate('', xy=(1, 0), xytext=(0, 0),
                    arrowprops=dict(arrowstyle='->', color='red', lw=2))
    axes[0].annotate('', xy=(0, 1), xytext=(0, 0),
                    arrowprops=dict(arrowstyle='->', color='green', lw=2))

    axes[0].set_xlim(-2.5, 2.5)
    axes[0].set_ylim(-2.5, 2.5)
    axes[0].set_aspect('equal')
    axes[0].set_title('Před transformací')

    # Transformovaná mřížka
    for i in np.linspace(-2, 2, 9):
        # Horizontální čáry
        line = np.array([[-2, i], [2, i]]).T
        trans_line = A @ line
        axes[1].plot(trans_line[0], trans_line[1], 'blue', alpha=0.3)

        # Vertikální čáry
        line = np.array([[i, -2], [i, 2]]).T
        trans_line = A @ line
        axes[1].plot(trans_line[0], trans_line[1], 'blue', alpha=0.3)

    # Transformované jednotkové vektory
    e1 = A @ np.array([1, 0])
    e2 = A @ np.array([0, 1])
    axes[1].annotate('', xy=e1, xytext=(0, 0),
                    arrowprops=dict(arrowstyle='->', color='red', lw=2))
    axes[1].annotate('', xy=e2, xytext=(0, 0),
                    arrowprops=dict(arrowstyle='->', color='green', lw=2))

    axes[1].set_xlim(-2.5, 2.5)
    axes[1].set_ylim(-2.5, 2.5)
    axes[1].set_aspect('equal')
    axes[1].set_title(f'Po transformaci: {title}')

    plt.tight_layout()
    plt.show()

# Ukázky
vizualizuj_transformaci(np.array([[2, 0], [0, 1]]), "Roztažení v x")
vizualizuj_transformaci(rotacni_matice(30), "Rotace 30°")
vizualizuj_transformaci(np.array([[1, 0.5], [0, 1]]), "Zkosení")

Efekt matice na mřížku


11.5 Aplikace

11.5.1 Transformace v grafice

# Jednoduchý domeček
import numpy as np
import matplotlib.pyplot as plt

dum = np.array([
    [0, 0],   # levý dolní
    [2, 0],   # pravý dolní
    [2, 1.5], # pravý horní
    [1, 2.5], # špička střechy
    [0, 1.5], # levý horní
    [0, 0]    # zpět na začátek
]).T

fig, axes = plt.subplots(2, 3, figsize=(12, 8))
axes = axes.flatten()

transformace = [
    (np.eye(2), "Původní"),
    (np.array([[1.5, 0], [0, 1]]), "Širší"),
    (np.array([[1, 0], [0, 1.5]]), "Vyšší"),
    (rotacni_matice(15), "Nakloněný"),
    (np.array([[-1, 0], [0, 1]]), "Zrcadlený"),
    (np.array([[0.8, 0.3], [0.1, 0.9]]), "Deformovaný")
]

for ax, (T, title) in zip(axes, transformace):
    trans_dum = T @ dum
    ax.fill(trans_dum[0], trans_dum[1], alpha=0.5, color='orange')
    ax.plot(trans_dum[0], trans_dum[1], 'brown', linewidth=2)
    ax.set_xlim(-3, 4)
    ax.set_ylim(-1, 4)
    ax.set_aspect('equal')
    ax.set_title(title)
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Animace transformací

11.5.2 Neuronová síť jako série transformací

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

# Vstupní data (kruh)
n = 100
theta = np.linspace(0, 2*np.pi, n)
X = np.vstack([np.cos(theta), np.sin(theta)])

# Váhy vrstev (náhodné matice)
W1 = np.random.randn(2, 2)
W2 = np.random.randn(2, 2)

# Transformace
H1 = W1 @ X
H2 = W2 @ H1

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

axes[0].scatter(X[0], X[1], c=theta, cmap='hsv', s=20)
axes[0].set_title('Vstup (kruh)')

axes[1].scatter(H1[0], H1[1], c=theta, cmap='hsv', s=20)
axes[1].set_title('Po 1. vrstvě (W₁ @ X)')

axes[2].scatter(H2[0], H2[1], c=theta, cmap='hsv', s=20)
axes[2].set_title('Po 2. vrstvě (W₂ @ H₁)')

for ax in axes:
    ax.set_aspect('equal')
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Neuronová síť transformuje data

11.6 Řešené příklady

11.6.1 Příklad 1: Rotace bodu

Otočte bod [3, 0] o 90° proti směru hodinových ručiček.

import numpy as np

R90 = rotacni_matice(90)
bod = np.array([3, 0])
rotovany = R90 @ bod

print(f"Rotační matice pro 90°:\n{R90.round(3)}")
print(f"\nPůvodní bod: {bod}")
print(f"Po rotaci: {rotovany.round(3)}")
Rotační matice pro 90°:
[[ 0. -1.]
 [ 1.  0.]]

Původní bod: [3 0]
Po rotaci: [0. 3.]

11.6.2 Příklad 2: Složená transformace

Vytvořte matici, která nejprve zmenší na polovinu a pak otočí o 45°.

import numpy as np

S = np.array([[0.5, 0], [0, 0.5]])  # Zmenšení
R = rotacni_matice(45)              # Rotace

# Složená transformace (pozor na pořadí!)
C = R @ S  # Nejprve S, pak R

print("Složená matice (rotace @ zmenšení):")
print(C.round(3))

# Test
bod = np.array([2, 0])
vysledek = C @ bod
print(f"\nBod [2, 0] po transformaci: {vysledek.round(3)}")
Složená matice (rotace @ zmenšení):
[[ 0.354 -0.354]
 [ 0.354  0.354]]

Bod [2, 0] po transformaci: [0.707 0.707]

11.6.3 Příklad 3: Identifikace transformace

Jakou transformaci provádí matice \(\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\)?

import numpy as np

A = np.array([[0, -1], [1, 0]])

# Aplikujeme na jednotkové vektory
e1 = np.array([1, 0])
e2 = np.array([0, 1])

print(f"[1, 0] → {A @ e1}")
print(f"[0, 1] → {A @ e2}")
print("\nJde o rotaci o 90° proti směru hodinových ručiček!")
[1, 0] → [0 1]
[0, 1] → [-1  0]

Jde o rotaci o 90° proti směru hodinových ručiček!

11.7 Cvičení

VarováníCvičení 1: Škálovací matice

Vytvořte matici, která ztrojnásobí x-ovou souřadnici a zachová y-ovou.

Výsledek: \(\begin{bmatrix} 3 & 0 \\ 0 & 1 \end{bmatrix}\)

VarováníCvičení 2: Rotace

Jaká je rotační matice pro 180°?

Výsledek: \(\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}\)

VarováníCvičení 3: Identita transformace

Co dělá matice \(\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\)?

Výsledek: Zrcadlení přes osu x

VarováníCvičení 4: Složená transformace

Jaká je matice pro zrcadlení přes osu y následované rotací o 90°?

Řešení
import numpy as np

My = np.array([[-1, 0], [0, 1]])
R90 = rotacni_matice(90)
C = R90 @ My
print(C.round(3))
# Výsledek: [[0, 1], [1, 0]]
VarováníCvičení 5: Inverzní transformace

Pokud matice R rotuje o 30°, jaká matice “vrátí” rotaci zpět?

Odpověď: Rotace o -30° (nebo transpozice R, protože rotační matice jsou ortogonální)


11.8 Shrnutí

PoznámkaCo si zapamatovat
  • Každá matice reprezentuje lineární transformaci
  • Škálování: \(\begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix}\)
  • Rotace o θ: \(\begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\)
  • Zrcadlení přes x: \(\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\)
  • Transformace se skládají násobením matic
  • Pořadí záleží: \(\mathbf{AB} \neq \mathbf{BA}\)
  • Neuronové sítě jsou řetězce lineárních transformací + nelineární aktivace

Dokončili jsme část o vektorech a maticích! V další části se ponoříme do derivací a gradientů – matematického aparátu, který umožňuje neuronové sítě trénovat.