Определитель, обратная матрица, ранг и системы уравнений

⏱ 35 мин · 🧩 заданий: 6

Определитель: во сколько раз меняется площадь

Линейное преобразование превращает единичный квадрат (построенный на e_1 и e_2) в параллелограмм. Определитель \det A — площадь этого параллелограмма со знаком. А раз сетка равномерная, любая фигура меняет площадь в те же |\det A| раз.

Для матрицы 2×2:

\det\begin{pmatrix} a & b \\ c & d \end{pmatrix} = ad - bc
  • |\det A| > 1 — площади растут, < 1 — уменьшаются;
  • \det A < 0 — ориентация перевернулась (как в зеркале);
  • \det A = 0 — плоскость схлопнулась в прямую или точку.

Вернитесь к виджету и посмотрите на закрашенный квадрат — его площадь равна |\det|:

import numpy as np
import vis

for M in ([[2, 0], [0, 1.5]], [[1, 1], [0, 1]], [[0, 1], [1, 0]], [[1, 2], [0.5, 1]]):
    M = np.array(M)
    print(M.tolist(), "det =", round(float(np.linalg.det(M)), 3))
    vis.transform(M, title=f"det = {np.linalg.det(M):.2f}")

Для матриц 3×3 определитель — изменение объёма, для n×n — n-мерного объёма. Считать его руками больших матриц не нужно: np.linalg.det.

Важное свойство: \det(AB) = \det A \cdot \det B — если одно преобразование удваивает площади, а другое утраивает, то их композиция увеличит в 6 раз.

Обратная матрица

Обратная матрица A^{-1} отменяет преобразование: A^{-1}A = AA^{-1} = I. Если A повернула плоскость на 30°, то A^{-1} повернёт на −30°.

Обратная существует тогда и только тогда, когда \det A \ne 0. Если пространство схлопнулось в прямую, разные точки попали в одну — по результату уже не восстановить, откуда они пришли. Такие матрицы называют вырожденными (singular).

import numpy as np

A = np.array([[4.0, 7], [2, 6]])
A_inv = np.linalg.inv(A)
print(A_inv)
print(A_inv @ A)                     # единичная матрица (с точностью до округления)

x = np.array([1.0, 2])
print("A·x =", A @ x, " → A⁻¹·(A·x) =", A_inv @ (A @ x))
import numpy as np

S = np.array([[2.0, 4], [1, 2]])     # первая строка = 2 × вторая
print("det =", np.linalg.det(S))
try:
    print(np.linalg.inv(S))
except np.linalg.LinAlgError as e:
    print("ошибка:", e)

На обычном компьютере NumPy бросит LinAlgError: Singular matrix. Браузерная сборка NumPy такую проверку не делает и молча вернёт nan («не число»). Поэтому перед обращением матрицы полезно самим проверить определитель или ранг.

Для 2×2 есть явная формула: \begin{pmatrix} a & b \\ c & d \end{pmatrix}^{-1} = \frac{1}{ad - bc}\begin{pmatrix} d & -b \\ -c & a \end{pmatrix} — деление на определитель сразу показывает, почему при \det = 0 ничего не выйдет.

Ранг

Ранг матрицы — размерность пространства, которое получается после преобразования (размерность «образа»). Это же — число линейно независимых столбцов (или строк).

Матрица 3×3 сжимает пространство Ранг det
никак (объём сохраняет «толщину») 3 ≠ 0
на плоскость 2 0
на прямую 1 0
в точку (нулевая матрица) 0 0
import numpy as np

A = np.array([[1, 2, 3], [4, 5, 6], [5, 7, 9]])   # третья строка = первая + вторая
print("ранг:", np.linalg.matrix_rank(A), " det ≈", round(float(np.linalg.det(A)), 10))

B = np.outer([1, 2, 3], [1, 0, -1])                # все строки пропорциональны
print(B)
print("ранг:", np.linalg.matrix_rank(B))

Линейно зависимые признаки в данных (например, цена в рублях и та же цена в долларах) делают матрицу X^TX вырожденной — так в ML появляется проблема мультиколлинеарности.

Системы линейных уравнений

Система

\begin{cases} 2x + y = 5 \\ x - 3y = -1 \end{cases}

записывается как A\mathbf{x} = \mathbf{b}, где A = \begin{pmatrix} 2 & 1 \\ 1 & -3 \end{pmatrix}, \mathbf{b} = \begin{pmatrix} 5 \\ -1 \end{pmatrix}. Геометрически: какой вектор A переводит в \mathbf{b}? Если A обратима, ответ единственный: \mathbf{x} = A^{-1}\mathbf{b}.

import numpy as np

A = np.array([[2.0, 1], [1, -3]])
b = np.array([5.0, -1])
x = np.linalg.solve(A, b)        # решает систему, не вычисляя обратную явно
print("решение:", x)
print("проверка A·x =", A @ x)

solve, а не inv

np.linalg.solve(A, b) быстрее и точнее, чем np.linalg.inv(A) @ b. Явно обращать матрицу почти никогда не нужно.

Метод наименьших квадратов: первая обученная модель

Вернёмся к квартирам. Точек много (10), а параметров два (w и b). Уравнений больше, чем неизвестных: прямая не пройдёт через все точки, точного решения нет. Найдём наилучшее — с минимальной суммой квадратов ошибок.

Запишем модель матрично. Матрица X имеет два столбца: площади и единицы (единица умножается на b). Вектор параметров \theta = (w, b). Тогда предсказания — X\theta, и мы хотим минимизировать \|X\theta - y\|^2.

Ответ даёт нормальное уравнение (его вывод — через производные, которые будут в следующем модуле):

\theta = (X^T X)^{-1} X^T y
import numpy as np
import vis

areas  = np.array([32, 38, 45, 50, 56, 63, 70, 78, 85, 95], dtype=float)
prices = np.array([6.8, 7.9, 9.1, 10.4, 11.0, 12.9, 13.8, 15.6, 16.5, 19.2])

X = np.c_[areas, np.ones(len(areas))]          # столбцы: площадь, 1
theta = np.linalg.solve(X.T @ X, X.T @ prices)
w, b = theta
mse = ((X @ theta - prices) ** 2).mean()
print(f"w = {w:.4f}, b = {b:.4f}, MSE = {mse:.4f}")
print(f"квартира 60 м² ≈ {w * 60 + b:.2f} млн ₽")

vis.line(areas, {"данные": prices, "наилучшая прямая": X @ theta},
         title="Метод наименьших квадратов", xlabel="площадь, м²", ylabel="цена, млн ₽")

Это настоящая линейная регрессия — модель, обученная на данных. Почему же нейросети учат не так, а градиентным спуском?

  • Формула работает только для линейной модели с квадратичной ошибкой. Для нейросетей замкнутой формулы нет.
  • Обращение матрицы d \times d стоит порядка d^3 операций: при миллионе признаков это невозможно.

Градиентный спуск лишён обоих ограничений — к нему мы и идём.

Итог

  • \det A — во сколько раз меняется площадь (объём); знак — ориентация; \det(AB) = \det A \det B.
  • \det A = 0 — пространство схлопнулось, матрица вырождена, обратной нет.
  • A^{-1} отменяет преобразование; системы Ax = b решают np.linalg.solve.
  • Ранг — размерность образа = число независимых столбцов.
  • Наименьшие квадраты: \theta = (X^TX)^{-1}X^Ty — точное решение линейной регрессии; для нейросетей нужен градиентный спуск.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Ввод ответа

Чему равен определитель матрицы [[3, 1], [4, 2]]?

Задание 2 Заполнить таблицу

Есть ли у матрицы обратная?

естьнет
[[1, 2], [2, 4]]
[[0, -1], [1, 0]] (поворот)
[[1, 0], [0, 0]] (проекция)
[[2, 0], [0, 0.5]]
[[1, 2, 3], [4, 5, 6], [5, 7, 9]]
Отметьте ячейку — «+», пустая — «−».
Задание 3 Один вариант ответа

Чему равен ранг матрицы 3×3, которая сжимает всё пространство на одну прямую?

Задание 4 Один вариант ответа

Что вернёт np.linalg.det(A @ B), если det(A) = 2, det(B) = -3?

Задание 5 Программа на Python

Напишите на чистом Python (без NumPy):

  • det2(M) — определитель матрицы 2×2 (список списков);
  • inv2(M) — обратную матрицу 2×2 по формуле
\begin{pmatrix} a & b \\ c & d \end{pmatrix}^{-1} = \frac{1}{ad - bc}\begin{pmatrix} d & -b \\ -c & a \end{pmatrix}

Если определитель равен 0, inv2 должна бросить ValueError.

Какие тесты проверяют код (3)
assert det2([[3, 1], [4, 2]]) == 2 and det2([[1, 2], [2, 4]]) == 0
Mi = inv2([[4, 7], [2, 6]])
expected = [[0.6, -0.7], [-0.2, 0.4]]
assert all(abs(Mi[i][j] - expected[i][j]) < 1e-12 for i in range(2) for j in range(2)), f"Получено {Mi}"

try:
    inv2([[1, 2], [2, 4]])
    assert False, "Для вырожденной матрицы нужен ValueError"
except ValueError:
    pass

Задание 6 Программа на Python

Метод наименьших квадратов. Даны площади x и цены y (векторы длины N). Напишите fit_line(x, y), которая возвращает (w, b) — параметры прямой y ≈ w·x + b с минимальной суммой квадратов ошибок. Используйте нормальное уравнение \theta = (X^T X)^{-1} X^T y, где у матрицы X два столбца: x и столбец единиц (решайте систему через np.linalg.solve). Верните обычные float.

Какие тесты проверяют код (2)
x = np.array([0.0, 1, 2, 3])
w, b = fit_line(x, 2 * x + 1)
assert abs(w - 2) < 1e-9 and abs(b - 1) < 1e-9, f"Для точек на прямой y = 2x + 1 получено w={w}, b={b}"

rng = np.random.default_rng(0)
x = rng.uniform(20, 100, 50)
y = 0.2 * x + 0.5 + rng.normal(0, 0.5, 50)
w, b = fit_line(x, y)
w2, b2 = np.polyfit(x, y, 1)
assert abs(w - w2) < 1e-8 and abs(b - b2) < 1e-6
assert isinstance(w, float) and isinstance(b, float), "Верните обычные float"

Войдите, чтобы отмечать пройденные уроки.