#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) что результат вашего задания.
Комментариев нет:
Отправить комментарий