Преобразования (разложение) матриц

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

Матричные преобразования (или по-другому, декомпозиции) — это методы, которые разлагают матрицу на составные части, что облегчает вычисление более сложных матричных операций. Методы матричной декомпозиции, также называемые методами матричной факторизации, являются основой в алгоритмах линейной алгебры, таких как решение систем линейных уравнений, вычисление обратной матрицы или определителя.

В частности, в машинном обучении широко используется сингулярное разложение (Singular Values Decomposition, SVD), которое позволяет представить исходную матрицу как произведение трех других матриц. SVD-разложение используется при решении самых разных задач — от приближения методом наименьших квадратов до сжатия и распознавания изображений.

Список доступных методов:

  • Cholesky — вычисление декомпозиции Холецкого;
  • Eig — вычисление собственных значений и правых собственных векторов квадратной матрицы;
  • EigVals — вычисление собственных значений общей матрицы;
  • LU — LU-факторизация матрицы как произведения нижнетреугольной матрицы и верхнетреугольной матрицы;
  • LUP — LUP-факторизация с частичным поворотом, которая является LU-факторизацией только с перестановками строк: PA=LU;
  • QR — QR-факторизация матрицы;
  • SVD — разложение по сингулярным значениям.

Ниже представлены прототипы методов.

bool matrix<T>::Cholesky(matrix<T> &L)

bool matrix<T>::Eig(matrix<T> &eigen_vectors, vector<T> &eigen_values)

bool matrix<T>::EigVals(vector<T> &eigen_values)

bool matrix<T>::LU(matrix<T> &L, matrix<T> &U)

bool matrix<T>::LUP(matrix<T> &L, matrix<T> &U, matrix<T> &P)

bool matrix<T>::QR(matrix<T> &Q, matrix<T> &R)

bool matrix<T>::SVD(matrix<T> &U, matrix<T> &V, vector<T> &singular_values)

Покажем пример сингулярного разложения методом SVD (см. файл MatrixSVD.mq5). Сначала инициализируем исходную матрицу.

matrix a = {{012345678}};
a = a - 4;
a.Reshape(33);
Print("matrix a \n"a);

Сделаем SVD-разложение:

matrix UV;
vector singular_values;
a.SVD(UVsingular_values);
Print("U \n"U);
Print("V \n"V);
Print("singular_values = "singular_values);

Проверим разложение: должно выполняться равенство U * "singular diagonal" * V = A.

matrix matrix_s;
matrix_s.Diag(singular_values);
Print("matrix_s \n"matrix_s);
matrix matrix_vt = V.Transpose();
Print("matrix_vt \n"matrix_vt);
matrix matrix_usvt = (U.MatMul(matrix_s)).MatMul(matrix_vt);
Print("matrix_usvt \n"matrix_usvt);

Сравним полученную и исходную матрицу на ошибки.

ulong errors = (int)a.Compare(matrix_usvt1e-9);
Print("errors="errors);

В журнале должно получиться следующее:

matrix a
[[-4,-3,-2]
 [-1,0,1]
 [2,3,4]]
U
[[-0.7071067811865474,0.5773502691896254,0.408248290463863]
 [-6.827109697437648e-17,0.5773502691896253,-0.8164965809277256]
 [0.7071067811865472,0.5773502691896255,0.4082482904638627]]
V
[[0.5773502691896258,-0.7071067811865474,-0.408248290463863]
 [0.5773502691896258,1.779939029415334e-16,0.8164965809277258]
 [0.5773502691896256,0.7071067811865474,-0.408248290463863]]
singular_values = [7.348469228349533,2.449489742783175,3.277709923350408e-17]
  
matrix_s
[[7.348469228349533,0,0]
 [0,2.449489742783175,0]
 [0,0,3.277709923350408e-17]]
matrix_vt
[[0.5773502691896258,0.5773502691896258,0.5773502691896256]
 [-0.7071067811865474,1.779939029415334e-16,0.7071067811865474]
 [-0.408248290463863,0.8164965809277258,-0.408248290463863]]
matrix_usvt
[[-3.999999999999997,-2.999999999999999,-2]
 [-0.9999999999999981,-5.977974170712231e-17,0.9999999999999974]
 [2,2.999999999999999,3.999999999999996]]
errors=0

Еще один практический случай использования метода Convolve включен в пример в разделе Методы машинного обучения.