#python #numpy #numpy-ndarray
#питон #тупой #numpy-ndarray
Вопрос:
У меня есть матрица с неупорядоченными записями. В качестве примера A = [a1, a2]
приведена типичная матрица с разделами a1 и a2 (a1 и a2 не обязательно являются скалярами, но могут быть подмассивами). Вместо этого моя матрица находится в порядке A = [a2, a1]
.
Я все еще хочу выполнить обычное матричное умножение, как если бы A было в правильном порядке. Есть ли способ сделать это без копирования?
Примером использования для этого является умножение по циклическому буферу. Я пытался избежать использования numpy.roll для буфера. Часто циклический буфер фрагментирован, но я просто хочу размножить его, так как я знаю, где фрагменты буфера.
Просто кажется, что независимо от того, что я делаю, мне в конечном итоге придется распределять элементы, равные по размеру конечному матричному произведению, потому что умножение на любой раздел A по-прежнему будет иметь одинаковое количество столбцов, поэтому конечные размеры не изменятся с A1 (часть A, которая будет умножать раздел 1) будет m x k1
и раздел будет k1 x n
(где k1 — количество строк в разделе).
np.matmul
похоже, у него нет возможности добавлять в существующий массив вместо его перезаписи. Это просто беспокоит меня, так как не должно требоваться другого распределения, поскольку элементы просто расположены в другом порядке. Я полагал, что мог бы просто сопоставить элементы соответствующим образом, но оказалось, что это гораздо сложнее.
Пример:
data = np.empty((10, 3))
buffer = CircularBuffer(data)
for i in range(10):
data.push(i)
# buffer now reads [[0, 0, 0], [1, 1, 1], ...]
data.push(-1)
data.push(-2)
# buffer overwrites oldest element
# reads [[-1, -1, -1], [-2, -2, -2], [2, 2, 2], ...]
A = np.arange(30).reshape(3, 10)
# We want this to perform A @ [[2, 2, 2], ..., [-1, -1, -1], [-2, 2, -2]]
# buf_start buf_end
# Unfortunately, the buffer is out of order!
A @ buffer
Очевидно, что в буфере есть два «раздела». От начала буфера до конца элемента хранения [[2, 2, 2], ...]
и от начала элемента хранения до конца буфера [[-1, -1, -1], [-2, -2, -2]]
.
Мы знаем порядок, в котором они должны быть (показан в коде), но мы хотим, чтобы умножение было выражено в порядке БУФЕРА, а не в самих необработанных данных, и я бы хотел избежать копирования.
Комментарии:
1. Не могли бы вы, пожалуйста, добавить воспроизводимый ввод, чтобы другие могли помочь вам с решением. Спасибо!
2. «Я все еще хочу выполнить обычное умножение матриц». Возможно, вы пропустили упоминание матриц, которые вы хотите умножить вместе.
3. «поскольку X будет m x k1». Что здесь означает X?
4. Я добавил пример. Извините за отсутствие ясности у всех. Также X была опечаткой, я имел в виду A, но да, обновлено для ясности.
5. Не имеет значения, являются ли строки
buffer
перестановкой или более общим подмножеством (или даже надмножеством с дубликатами). Это отличается от оригинала. Столбцы A` должны быть в порядке соответствия.. при выполненииA@B
имеют значение текущие значения, а не история..
Ответ №1:
В опубликованном вопросе упоминается, что A = [a1, a2]
where a1
и a2
могут быть подмассивами, а не скалярами.
Соответственно, для моего рабочего примера я определил A.shape
как (10, 3, 2)
. Согласно numpy
правилам умножения матриц (применимым np.matmul()
как к @
оператору, так и к оператору, а также к np.dot()
), A @ buffer
чтобы быть действительным, последнее измерение A
должно соответствовать предпоследнему измерению buffer
. Следовательно, я определил buffer.shape
как (10, 2, 3)
. (Обратите внимание на разницу с формой A
)
Вот моя инициализация A
и buffer
:
A = np.arange(60).reshape (10, 2, 3)
buffer = -1 * np.arange(60).reshape (10, 3, 2)
Тогда, с этими формами, A @ buffer
будет иметь форму (10, 2, 2)
. Следовательно, чтобы сохранить результат умножения матрицы, я определяю массив my_result
как:
my_result = np.empty(A.shape[:-1] buffer.shape[-1:]) # To hold the result of A @ buffer
Теперь в вопросе упоминается, что строки buffer
не в порядке.
Пусть k
— индекс (on axis0
of buffer
), при котором «буфер фрагментирован / разделен». (Следовательно, 0 <= k <= 9
).
k = 2
Затем, вместо выполнения умножения матрицы между A
и buffer
за один раз, это можно выполнить в два этапа, как показано ниже:
np.matmul(A[:k], buffer[-k:], out=my_result[:k]) # Fills a part of my_result
np.matmul(A[k:], buffer[:-k], out=my_result[k:]) # Fills the other part of my_result
Тестирование:
my_result1 = np.matmul(A, np.roll(buffer, k, axis=0))
np.array_equal(my_result, my_result1)
Вывод:
Верно
Подводя итог, можно сказать, что то, что мы здесь делаем, это:
- Выделите неинициализированный массив
my_result
для хранения результатаmatmul()
- Вызывайте
matmul()
дважды, каждый раз передавая другой фрагментmy_result
в качестве значенияout
параметра ofmatmul()
и заботясь об индексацииA
иbuffer
правильном пути.
Насколько я могу судить, здесь нет избыточной копии данных, если только вы np.empty()
не считаете это какой-то копией данных. Это просто исходное умножение матрицы, происходящее в два приема.
Комментарии:
1. Я полагаю, что элементы A должны быть не в порядке вдоль другой оси.
2. @user2357112 supportsmonica верен, но мне интересно, можно ли достичь того же эффекта путем транспонирования и отмены транспонирования. Использует ли транспонирование память?
3. @EmmyChow —
np.transpose(a)
создает новыйnumpy
массив , который использует тот же базовый блок памяти , что и его входныеa
данные . Что касается описания вашей проблемы, вы четко упомянули, что для целей умноженияA @ buffer
, несмотря на то, что строка[-1,-1,-1]
и строка[-2,-2,-2]
buffer
присутствуют в index0
и index1
(по оси0
) соответственно, вы хотели, чтобы умножение вело себя так, как если бы они присутствовали в index-2
и index-1
соответственно. Другими словами, проблема «не по порядку» возникает вдоль оси0
, а не оси1
. Это именно то, к чему относится мой ответ.4. @EmmyChow — Везде вы только упомянули, что СТРОКИ не в порядке. Нигде вы не упоминали, что элементы внутри строки не в порядке. Мой ответ основан на этом описании. В чем же проблема?
5. @fountainhead Да, строки не в порядке, однако я на самом деле не заставляю ваше решение работать. Я продолжаю получать несоответствия размеров. Можете ли вы где-нибудь привести полный пример, чтобы показать мне?