Давайте начнем с небольшого признания: несмотря на то, что я провел более полувека, работая в области машинного обучения (а до этого потратил три года на разработку актуарного программного обеспечения, еще одного типа математических вычислений), я не так хорошо справлялся с математикой в ​​первые несколько лет. годы колледжа. На самом деле, я даже провалил дифференциальное исчисление в первый раз, когда сдавал его в Колледже Статен-Айленда, учреждении, не обязательно известном своей академической интенсивностью. Очевидно, я разобрался с этим, но, несмотря на мой карьерный опыт, некоторые мои математические знания не так прочны, как хотелось бы.

Работая в области машинного обучения и с учеными-данными, я всегда хотел отточить свои знания в области линейной алгебры (я преуспел в дифференциальном исчислении, когда взял его снова, а также в интегральном и многомерном :)). В университете это всегда казалось мне очень «механическим» предметом: вы занимаетесь простой алгеброй и надеетесь, что не совершите ошибку, которая распространяется вниз, будь то реальная вычислительная ошибка или просто запись 1 в странной форме. образом и приняв его за 7 или что-то позже. У меня все было хорошо, но я так и не усвоил это и не чувствовал себя психологически комфортно, как я занимался исчислением, логикой, теорией множеств или вероятностью. Я действительно глубоко верю, что каждый может выучить математику, и это вопрос времени, настойчивости и поиска учебного материала, который вам точно понравится. С этой целью я получил копию Introduction to Linear Algebra доктора Гилберта Стрэнга и начал просматривать ее раз в шесть месяцев, поскольку жизнь, работа, кошки и все остальное перепрыгивали через мой приоритет. список.

Но недавно я почувствовал, что это не оправдание — я могу уделить этому немного времени, не так ли? С этой целью я понемногу прорабатывал учебник доктора Стрэнга, выполняя большинство упражнений из каждого раздела, пока не достиг определенного уровня понимания. Медленно, но прогресс есть прогресс.

Одной из важных частей этого процесса является проверка моей работы. Вышеупомянутое распространение небольших ошибок, безусловно, является проблемой при изучении линейной алгебры, и я не хочу выкручиваться, просто проверяя конец учебника или подключая все к какому-либо решателю. Золотая середина для меня — это использовать NumPy, чтобы проверить, например, что я нашел правильное решение для конкретного Ax=b. Сделать это на самом деле довольно просто, но мне потребовался день, чтобы понять, что я могу это сделать, поэтому я решил написать несколько слов об этом.

Одна задача в разделе 1.3 Странга дает несколько матриц, в которых один элемент c не определен, и читателю нужно выбрать c, чтобы сделать матрицу единственной. То, как я решил это, довольно просто; возьмите строки/столбцы, в которых определены все элементы, и посмотрите, как определенные элементы оставшихся «свободных» строк/столбцов могут быть выражены в виде их линейной комбинации. Возьмем этот пример:

# c1 c2 c3
[
  [1, 3, 5],
  [1, 2, 4],
  [1, 1, x],
]

Здесь с3 = 2с1 + с2. Это, конечно, без учета неопределенного x . Итак, если c3 действительно равно 2c1 + c2, то x=3, c3 = [1, 1, 3] «решит» матрицу, сделав ее сингулярной. И мы можем перепроверить это; numpy.linalg.inv должен выдать ошибку, если это так. Например:

import numpy as np
A = np.array([
  [1, 3, 5],
  [1, 2, 4],
  [1, 1, 3],
])
np.linalg.inv(A)

Запустив это, вы получите:

---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
Cell In[2], line 6
      1 A = np.array([
      2   [1, 3, 5],
      3   [1, 2, 4],
      4   [1, 1, 3],
      5 ])
----> 6 np.linalg.inv(A)

File <__array_function__ internals>:200, in inv(*args, **kwargs)

File ~/.cache/pypoetry/virtualenvs/linear-algebra-pdghZUB5-py3.10/lib/python3.10/site-packages/numpy/linalg/linalg.py:538, in inv(a)
    536 signature = 'D->D' if isComplexType(t) else 'd->d'
    537 extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
--> 538 ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
    539 return wrap(ainv.astype(result_t, copy=False))

File ~/.cache/pypoetry/virtualenvs/linear-algebra-pdghZUB5-py3.10/lib/python3.10/site-packages/numpy/linalg/linalg.py:89, in _raise_linalgerror_singular(err, flag)
     88 def _raise_linalgerror_singular(err, flag):
---> 89     raise LinAlgError("Singular matrix")

LinAlgError: Singular matrix

И, конечно же, мы можем проверить, является ли матрица обратимой. В этом случае он не должен выдавать LinAlgError, но если мы проверяем работоспособность, он должен выдавать ту же обратную матрицу, которую мы разработали вручную (возможно, с некоторыми ошибками округления с плавающей запятой). В задаче 12 того же раздела Стрэнг показывает «центрированную разностную матрицу» в R4:

[
  [ 0,  1,  0,  0],
  [-1,  0,  1,  0],
  [ 0, -1,  0,  1],
  [ 0,  0, -1,  0],
]

Вручную вы можете вычислить, что x2=b1, -x3=b4, а затем подставить для решения x1 и x4 с точки зрения b. np.linalg.inv также инвертирует эту матрицу. Однако Стрэнг также включает задачу, чтобы показать, что центрированная разностная матрица в R5 необратима, путем выбора ненулевого вектора b, который решает C5*b=0 . Вручную и посмотрев на матрицу, я понял, что c1+c3+c5=0, что вы можете перепроверить:

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

# remember, 0-based indexing with most PLs, 1-based indexing in mathematics
C5[0, :] + C5[2, :] + C5[4, :]

Это даст вам array([0, 0, 0, 0, 0]) , что, безусловно, является ответом, но, как только это распространяется на еще более высокие измерения, визуальный осмотр ndarray становится раздражающим и подверженным ошибкам. Таким образом, вы можете немного облегчить себе задачу, запустив что-то вроде ((C5[0, :] + C5[2, :] + C5[4, :]) == np.zeros(5)).all() . Однако этот однострочный код чувствителен к различиям в размерах матриц, поэтому следующим шагом будет создание для него нескольких вспомогательных модулей.

Я нахожу это довольно крутым, потому что многие учебники по языку программирования начинаются с демонстрации того, как использовать язык в качестве базового калькулятора. Но, как правило, вы этого не делаете, так что найти для этого реальное применение — дело аккуратное.

Довольно много слов для чего-то, что, оглядываясь назад, довольно прямолинейно. Я надеюсь, что вы получили некоторую пользу от этой статьи.