#python #математика #numpy #матрицы #деление
Имеется произведение матриц a*b=c. Причем произведение матриц - это результат numpy.dot,
а не поэлементное произведение. Известны матрицы a и c. Требуется найти матрицу b.
Каким образом это можно сделать в python, не прибегая к решению системы уравнений с
множеством неизвестных? Если просто делить numpy.matrix, то получается совсем не тот
результат.
Вот пример:
import numpy as np
a = np.matrix([[ 1., 2.],[ 3., 4.]])
c = np.matrix([[ 2.],[ 1.]])
c/a
Out[201]:
matrix([[ 2. , 1. ],
[ 0.33333333, 0.25 ]])
Решил письменно обратную задачу, получил ответ:
([[-3. ],
[ 2.5]])
Проверяем:
b= np.matrix([[-3. ],[ 2.5]])
a*b
Out[207]:
matrix([[ 2.],
[ 1.]])
Если переводить в ndarray, то то же самое получается:
c.getA()/a.getA()
Out[213]:
array([[ 2. , 1. ],
[ 0.33333333, 0.25 ]])
Ответы
Ответ 1
Воспользуйтесь обратной (inverse) матрицей:
In [224]: b = np.linalg.inv(a) * c
In [225]: b
Out[225]:
matrix([[-3. ],
[ 2.5]])
Это будет работать для объектов типа numpy.matrix.
Если a и c - объекты типа numpy.ndarray, то нужно использовать dot product (как в
ответе @MarianD):
In [8]: np.linalg.inv(a).dot(c)
Out[8]:
matrix([[-3. ],
[ 2.5]])
PS использование dot product (операции умножения матриц как это понимается в линейной
алгебре) - является более универсальным решением, т.к. оно правильно работает как для
объектов типа numpy.matrix так и для numpy.ndarray:
In [10]: np.linalg.inv(a.getA()).dot(c.getA())
Out[10]:
array([[-3. ],
[ 2.5]])
Пояснение:
A * B = C | умножим обе части на A-1
умножение матриц операция некомутативная, т.е. A * B != B * A, поэтому чтобы получилась
единичная матрица будем делать так:
A-1 * A * B = A-1 * C
=>
B = A-1 * C
UPDATE: во многих случаях гораздо выгоднее решить систему уравнений, по сравнению
с нахождением обратной матрицы (спасибо @jfs за подсказку):
In [328]: b = np.linalg.solve(a, c)
In [329]: b
Out[329]:
matrix([[-3. ],
[ 2.5]])
Вот некоторые из преимуществ подхода решения системы линейных уравнений по сравнению
с нахождением обратной матрицы:
решение СЛУ (системы линейных уравнений) дает более точные численные результаты по
сравнению с методами, использующими перемножение матриц. Пример скалярного произведения
возвращающего неточный результат
при использовании разреженных матриц (sparse matrices) есть методы, позволяющие найти
решение и возвращающие также разреженные матрицы (если это возможно), что существенно
экономит использование памяти. Обратная же матрица в общем случае не будет разреженной
и может занимать на несколько порядков больше памяти. Например разреженная матрица
размерности 1.000.000 x 1.000.000 у которой всего 1.000.000 ненулевых элементов (например
единичная матрица или такая, у которой в каждой строке/столбце по одному ненулевому
элементу) легко поместится в памяти и займет приблизительно: объем памяти необходимый
для данного типа (np.int8, np.int16, np.int32, np.int64, np.float64, etc.) плюс небольшие
накладные расходы (информация о позиции ненулевых элементов в разреженной матрице).
Если преобразовать такую матрицу в обычную или найти обратную ей то в результате надо
будет хранить в памяти уже 1.000.000 x 1.000.000 = 1.000.000.000.000 (один триллион
элементов, или около 3.6 TiB для 32-битных элементов)
Ответ 2
Произведением матриц очевидно во вашем случае не разумеется код
a * b
что в numpy значит просто произведение элементов на согласных позициях,
но математическое произведение (скалярное произведение строк матрицы a со столбцами
матрицы b, что в numpy записывают как
np.dot(a, b)
или - более просто -
a.dot(b)
(что нужно использовать для проверки результата).
Подобно этому, простое деление
c / a
делением элемент по элементу (с автоматическим расширением матрицы c на 2 x 2) на
согласных позициях - и это опять нет тем, что вам требуется).
Из-за того решение вашего задания маленько сложнее:
Tак как a * b = c влечет за собой (после произведения обух страниц уравнения слева
на а-1) b = а-1 * c. Это в numpy записывают как
np.dot(np.linalg.inv(a), c)
или - более просто -
np.linalg.inv(a).dot(c)
что результат вашего задания.