Умножение двух матриц
В Python матрицу удобно представлять как вложенный список — список списков, где каждый внутренний список является строкой матрицы. В этой статье разберём два способа умножать матрицы: классический с вложенными циклами и компактный — через списковое включение.
Что нужно знать
Перед изучением примера полезно понимать:
Python: цикл for — цикл
forPython: список (list) — списки
Матрицы и NumPy-массивы в Python — матрицы и NumPy
Python: list comprehension — списковые включения
Например, X = [[1, 2], [4, 5], [3, 6]] описывает матрицу 3×2. Первую строку можно получить как X[0], а элемент первой строки и первого столбца — как X[0][0].
Умножение матриц X и Y определено только когда число столбцов в X равно числу строк в Y. Если X имеет размер n × m, а Y — m × l, то XY имеет размер n × l (а вот YX в этом случае не определено).
Способ 1. Вложенные циклы
# Program to multiply two matrices using nested loops
# 3x3 matrix
X = [[12,7,3],\
[4 ,5,6],\
[7 ,8,9]]
# 3x4 matrix
Y = [[5,8,1,2],\
[6,7,3,0],\
[4,5,9,1]]
# result is 3x4
result = [[0,0,0,0],\
[0,0,0,0],\
[0,0,0,0]]
# iterate through rows of X
for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)
Вывод
[114, 160, 60, 27]
[74, 97, 73, 14]
[119, 157, 112, 23]
В этой программе три вложенных цикла for перебирают строки и столбцы матриц и накапливают сумму произведений в result. Способ простой, но вычислительно дорогой, особенно с ростом размерности матриц.
Совет
Для серьёзных операций над большими матрицами лучше использовать оптимизированную библиотеку NumPy — она работает в сотни и тысячи раз быстрее, чем код выше.
Способ 2. Вложенное списковое включение
# Program to multiply two matrices using list comprehension
# 3x3 matrix
X = [[12,7,3],\
[4 ,5,6],\
[7 ,8,9]]
# 3x4 matrix
Y = [[5,8,1,2],\
[6,7,3,0],\
[4,5,9,1]]
# result is 3x4
result = [[sum(a*b for a,b in zip(X_row,Y_col)) for Y_col in zip(*Y)] for X_row in X]
for r in result:
print(r)
Результат тот же, что и в первом примере. Чтобы понять этот код, полезно знать о встроенной функции zip() и о распаковке аргументов оператором *.
Здесь вложенное списковое включение проходит по элементам матриц и сразу собирает результат. Сначала может показаться, что код сложный и плохо читается, но как только вы привыкнете к списковым включениям, переключаться обратно на вложенные циклы вряд ли захочется.