Перемноженное матричное умножение в Numpy

#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 параметра of matmul() и заботясь об индексации 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 присутствуют в index 0 и index 1 (по оси 0 ) соответственно, вы хотели, чтобы умножение вело себя так, как если бы они присутствовали в index -2 и index -1 соответственно. Другими словами, проблема «не по порядку» возникает вдоль оси 0 , а не оси 1 . Это именно то, к чему относится мой ответ.

4. @EmmyChow — Везде вы только упомянули, что СТРОКИ не в порядке. Нигде вы не упоминали, что элементы внутри строки не в порядке. Мой ответ основан на этом описании. В чем же проблема?

5. @fountainhead Да, строки не в порядке, однако я на самом деле не заставляю ваше решение работать. Я продолжаю получать несоответствия размеров. Можете ли вы где-нибудь привести полный пример, чтобы показать мне?