Вот способ сделать это с TensorFlow:
import tensorflow as tf
data = tf.placeholder(tf.float32, [None, None])
n = tf.placeholder(tf.int32, [])
eye = tf.eye(n)
mult = data[:, tf.newaxis, :, tf.newaxis] * eye[tf.newaxis, :, tf.newaxis, :]
result = tf.reshape(mult, n * tf.shape(data))
with tf.Session() as sess:
a = sess.run(result, feed_dict={data: [[1, 2], [3, 4]], n: 3})
print(a)
Выход:
[[1. 0. 0. 2. 0. 0.]
[0. 1. 0. 0. 2. 0.]
[0. 0. 1. 0. 0. 2.]
[3. 0. 0. 4. 0. 0.]
[0. 3. 0. 0. 4. 0.]
[0. 0. 3. 0. 0. 4.]]
Кстати, вы можете сделать то же самое в NumPy, который должен быть быстрее, чем ваше текущее решение:
import numpy as np
data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult = data[:, np.newaxis, :, np.newaxis] * eye[np.newaxis, :, np.newaxis, :]
result = np.reshape(mult, (n * data.shape[0], n * data.shape[1]))
print(result)
# The output is the same as above
EDIT:
Я попытаюсь дать некоторую интуицию о том, почему / как это работает, извините, если это слишком долго. Это не так сложно, но я думаю, что это сложно объяснить. Может быть, легче увидеть, как работает следующее умножение
import numpy as np
data = np.array([[1, 2], [3, 4]])
n = 3
eye = np.eye(n)
mult1 = data[:, :, np.newaxis, np.newaxis] * eye[np.newaxis, np.newaxis, :, :]
Теперь mult1
является своего рода «матрицей матриц». Если я приведу два индекса, я получу диагональную матрицу для соответствующего элемента в исходном:
print(mult1[0, 0])
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
Таким образом, вы можете сказать, что эту матрицу можно визуализировать так:
| 1 0 0 | | 2 0 0 |
| 0 1 0 | | 0 2 0 |
| 0 0 1 | | 0 0 2 |
| 3 0 0 | | 4 0 0 |
| 0 3 0 | | 0 4 0 |
| 0 0 3 | | 0 0 4 |
Однако это обманчиво, потому что если вы попытаетесь изменить это до окончательной формы, результат будет неправильным:
print(np.reshape(mult1, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 0. 1. 0.]
# [0. 0. 1. 2. 0. 0.]
# [0. 2. 0. 0. 0. 2.]
# [3. 0. 0. 0. 3. 0.]
# [0. 0. 3. 4. 0. 0.]
# [0. 4. 0. 0. 0. 4.]]
Причина в том, что изменение формы (концептуально) сначала "выравнивает" массив, а затем дает новую форму. Но уплощенный массив в этом случае не то, что вам нужно:
print(mult1.ravel())
# [1. 0. 0. 0. 1. 0. 0. 0. 1. 2. 0. 0. 0. 2. 0. ...
Видите ли, сначала он пересекает первую подматрицу, затем вторую и т. Д. Однако вы хотите, чтобы он прошел сначала первую строку первой подматрицы, затем первую строку второй подматрицы, затем вторую строку первая подматрица и т. д. Итак, в основном вы хотите что-то вроде:
- Возьмите первые две подматрицы (те, которые имеют
1
и 2
)
- Взять все первые строки (
[1, 0, 0]
и [2, 0, 0]
).
- Возьмите первый из них (
[1, 0, 0]
)
- Взять каждый из его элементов (
1
, 0
и 0
).
А потом продолжай отдыхать. Итак, если подумать, мы сначала пересекаем ось 0 (строка «матрицы матриц»), затем 2 (строки каждой подматрицы), затем 1 (столбец «матрицы матриц») и, наконец, 3 (столбцы подматриц). ). Таким образом, мы можем просто изменить порядок оси, чтобы сделать это:
mult2 = mult1.transpose((0, 2, 1, 3))
print(np.reshape(mult2, (n * data.shape[0], n * data.shape[1])))
# [[1. 0. 0. 2. 0. 0.]
# [0. 1. 0. 0. 2. 0.]
# [0. 0. 1. 0. 0. 2.]
# [3. 0. 0. 4. 0. 0.]
# [0. 3. 0. 0. 4. 0.]
# [0. 0. 3. 0. 0. 4.]]
И это работает! Таким образом, в решении, которое я разместил, чтобы избежать транспонирования, я просто делаю умножение, чтобы порядок осей был именно таким:
mult = data[
:, # Matrix-of-matrices rows
np.newaxis, # Submatrix rows
:, # Matrix-of-matrices columns
np.newaxis # Submatrix columns
] * eye[
np.newaxis, # Matrix-of-matrices rows
:, # Submatrix rows
np.newaxis, # Matrix-of-matrices columns
: # Submatrix columns
]
Надеюсь, это немного прояснит. Честно говоря, в этом случае, в частности, я мог быстро найти решение, потому что мне пришлось решать аналогичную проблему не так давно, и я полагаю, что в итоге вы создали интуицию из этих вещей.