Дополнительные упражнения: векторы и матрицы
Как работать с уроком
Задания идут от простого к сложному: сначала вычисления на бумаге (берите ручку — это лучший способ запомнить), затем код. Если застряли — откройте подсказку или вернитесь к уроку:
- Векторы — длина, скалярное произведение, угол, проекция;
- Матрицы — формы и умножение;
- Преобразования — столбцы как образы базиса;
- Определитель и обратная;
- Собственные векторы.
Проверяйте ручные вычисления в песочнице:
import numpy as np
A = np.array([[1, 0, 2], [-1, 3, 1]])
B = np.array([[3, 1], [2, 1], [1, 0]])
print(A @ B)
print(np.linalg.det(np.array([[2.0, 1], [1, 1]])))
print(np.linalg.eigvals(np.array([[4.0, 1], [2, 3]])))
Разобранный пример: собственные значения вручную
Собственные значения — корни уравнения \det(A - \lambda I) = 0. Почему? Av = \lambda v \Leftrightarrow (A - \lambda I)v = 0, и ненулевое решение v существует, только если матрица A - \lambda I вырождена.
Для A = \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix}:
Собственный вектор для \lambda = 3: (A - 3I)v = 0, то есть -v_1 + v_2 = 0 — подходит v = (1, 1). Для \lambda = 1: v_1 + v_2 = 0 — подходит v = (1, -1). Матрица растягивает в 3 раза вдоль диагонали y = x и не меняет перпендикулярное направление.
import numpy as np
import vis
A = np.array([[2.0, 1], [1, 2]])
vals, vecs = np.linalg.eigh(A)
print(vals, vecs.round(3), sep="\n")
vis.transform(A, title="Растяжение в 3 раза вдоль y = x", vecs=[[1, 1], [1, -1]])
Разобранный пример: метод Гаусса
Последнее задание — классический алгоритм решения систем. Идея: вычитая из строк кратные других строк, привести матрицу к треугольному виду, а затем найти неизвестные с конца.
Если на диагонали оказался 0 (или очень маленькое число), делить на него нельзя (или опасно из-за погрешностей). Поэтому строки переставляют так, чтобы сверху был наибольший по модулю элемент, — это выбор главного элемента. Именно так (только на C и с оптимизациями) работает np.linalg.solve.
Шпаргалка по модулю
| Что | Формула | NumPy |
|---|---|---|
| Скалярное произведение | a \cdot b = \sum a_i b_i = \|a\|\|b\|\cos\theta | a @ b |
| Длина | \|a\| = \sqrt{a \cdot a} | np.linalg.norm(a) |
| Косинусная близость | \frac{a \cdot b}{\|a\|\|b\|} | |
| Произведение матриц | (m\times n)(n\times k) = (m \times k), c_{ij} = \sum_t a_{it}b_{tj} | A @ B |
| Транспонирование | (AB)^T = B^TA^T | A.T |
| Определитель 2×2 | ad - bc | np.linalg.det(A) |
| Обратная | A^{-1}A = I, есть при \det \ne 0 | np.linalg.inv(A) |
| Система | Ax = b | np.linalg.solve(A, b) |
| Ранг | размерность образа | np.linalg.matrix_rank(A) |
| Собственные | Av = \lambda v, \det(A - \lambda I) = 0 | np.linalg.eig, eigh |
| SVD | A = U\Sigma V^T | np.linalg.svd(A) |
Практика решено 0 из 13
Чему равно ‖(1, 2, 2)‖?
Найдите x, при котором векторы (2, x) и (3, -6) перпендикулярны.
Чему равен угол между векторами (1, 0) и (1, 1) в градусах?
Вычислите \begin{pmatrix} 1 & 0 & 2 \\ -1 & 3 & 1 \end{pmatrix} \begin{pmatrix} 3 & 1 \\ 2 & 1 \\ 1 & 0 \end{pmatrix}.
Ответ запишите в виде [[a, b], [c, d]].
Какой формы результат? (A: 4×3, B: 3×5, x: вектор из 3 чисел, y: вектор из 4 чисел)
| (4, 5) | (4,) | (3, 3) | число | ошибка | |
|---|---|---|---|---|---|
A @ B |
|||||
A @ x |
|||||
A.T @ A |
|||||
y @ A @ x |
|||||
B @ A |
|||||
x @ x |
Чему равен определитель матрицы [[2, 0, 0], [0, 3, 0], [0, 0, 0.5]]?
Найдите обратную к матрице [[2, 1], [1, 1]]. Ответ в виде [[a, b], [c, d]].
Матрица A переводит e₁ в (0, 2), а e₂ в (1, 0). Какая это матрица?
Найдите собственные значения матрицы [[4, 1], [2, 3]]. Перечислите через запятую по возрастанию.
Решите уравнение det(A − λI) = 0: (4 − λ)(3 − λ) − 1·2 = 0.
Напишите на чистом Python transpose(M) (список списков → транспонированный список списков)
и matvec(M, v) — умножение матрицы на вектор-список.
Какие тесты проверяют код (3)
assert transpose([[1, 2, 3], [4, 5, 6]]) == [[1, 4], [2, 5], [3, 6]] assert transpose([[7]]) == [[7]] assert matvec([[1, 2], [3, 4], [5, 6]], [10, 1]) == [12, 34, 56]
def transpose(M):
return [list(col) for col in zip(*M)]
def matvec(M, v):
return [sum(a * b for a, b in zip(row, v)) for row in M]
Проекция на прямую. Напишите project(a, u): проекцию вектора a на направление вектора u
(u не обязательно единичный). Формула: \dfrac{a \cdot u}{u \cdot u}\, u. NumPy-массивы на входе и выходе.
Какие тесты проверяют код (2)
assert np.allclose(project(np.array([3.0, 4]), np.array([2.0, 0])), [3, 0]) a, u = np.array([1.0, 2, 3]), np.array([1.0, 1, 0]) p = project(a, u) assert np.allclose(p, [1.5, 1.5, 0]) assert abs((a - p) @ u) < 1e-12, "Остаток a − p должен быть перпендикулярен u"
import numpy as np
def project(a, u):
return (a @ u) / (u @ u) * u
Ортонормированный базис (Грам–Шмидт). Напишите gram_schmidt(vectors): на входе список
линейно независимых NumPy-векторов, на выходе — список единичных взаимно перпендикулярных
векторов той же длины, задающих то же пространство. Алгоритм: для каждого вектора вычтите его
проекции на уже найденные векторы и нормализуйте остаток.
Какие тесты проверяют код (2)
Q = np.array(gram_schmidt([np.array([3.0, 1]), np.array([2.0, 2])])) assert np.allclose(Q @ Q.T, np.eye(2)), "Векторы должны быть единичными и перпендикулярными" assert np.allclose(Q[0], np.array([3, 1]) / np.sqrt(10)), "Первый вектор — нормализованный первый вход" rng = np.random.default_rng(0) vs = list(rng.normal(size=(4, 4))) Q = np.array(gram_schmidt(vs)) assert np.allclose(Q @ Q.T, np.eye(4), atol=1e-9)
import numpy as np
def gram_schmidt(vectors):
basis = []
for v in vectors:
w = v.astype(float)
for q in basis:
w = w - (w @ q) * q
basis.append(w / np.linalg.norm(w))
return basis
Решение системы методом Гаусса. Напишите gauss_solve(A, b) для квадратной системы
(A — список списков n×n, b — список из n чисел) без NumPy. Верните список решений.
Используйте выбор главного элемента: на каждом шаге ставьте наверх строку с наибольшим
по модулю элементом в текущем столбце.
Какие тесты проверяют код (3)
x = gauss_solve([[2, 1], [1, -3]], [5, -1])
assert all(abs(a - b) < 1e-9 for a, b in zip(x, [2, 1])), f"Получено {x}"
x = gauss_solve([[0, 1, 1], [1, 0, 1], [1, 1, 0]], [5, 4, 3])
assert all(abs(a - b) < 1e-9 for a, b in zip(x, [1, 2, 3])), "Первый элемент равен нулю — нужен выбор главного элемента"
import numpy as np
rng = np.random.default_rng(3)
A = rng.normal(size=(5, 5)); b = rng.normal(size=5)
assert np.allclose(gauss_solve(A.tolist(), b.tolist()), np.linalg.solve(A, b))
def gauss_solve(A, b):
n = len(b)
M = [list(map(float, row)) + [float(bi)] for row, bi in zip(A, b)]
for col in range(n):
pivot = max(range(col, n), key=lambda r: abs(M[r][col]))
M[col], M[pivot] = M[pivot], M[col]
for r in range(col + 1, n):
f = M[r][col] / M[col][col]
for c in range(col, n + 1):
M[r][c] -= f * M[col][c]
x = [0.0] * n
for i in range(n - 1, -1, -1):
x[i] = (M[i][n] - sum(M[i][j] * x[j] for j in range(i + 1, n))) / M[i][i]
return x
Войдите, чтобы отмечать пройденные уроки.