Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

Найти матрицу-множитель в произведении матриц при известном результате

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

Комментариев нет:

Отправить комментарий