Вычтите из последней оси ndarray - PullRequest
1 голос
/ 05 марта 2019

Я хочу вычесть все значения в a [nn, ..., 0] на b [nn], в то время как сохраняя исходную структуру массива a .


У меня проблема с индексацией и поэлементным вычитанием из массива ndnumpy. В моем случае массив a имеет 6 измерений

In[]: a.shape
Out[]: (101, 256, 1, 3, 1, 10)

Для согласованности самое низкое измерение N = 0 имеет 10 элементов, а самое высокое N = 5 имеет 101 элемент.

У меня также есть 1D массив b , который соответствует размеру самого высокого размерность в a .

In[]: b.shape
Out[]: (101,)

Я хочу вычесть b из a таким образом, чтобы nn -й элемент в b был вычитается из значений a [nn, ..., 0] . Я знаю, что могу сделать это, используя циклы for, но также должна быть возможность транслировать b таким образом, чтобы я мог использовать что-то вроде

In[]: c= a[:,...,0]-b[somehow broadcastet or reshaped]
In[]: c.shape()
Out[]:  (101, 256, 1, 3, 1, 10)

1 Ответ

1 голос
/ 05 марта 2019

Вы действительно могли бы сделать это, воспользовавшись вещанием .

Давайте начнем с генерации некоторой случайной ndarrays указанной формы, чтобы проверить, что окончательные размеры соответствуют ожидаемым:

a = np.random.rand(101, 256, 1, 3, 1, 10)
b = np.random.rand(101)

В этом случае вам придется добавить до a.ndim измерений к b, чтобы каждое значение в b вычиталось из каждого значения в последнем измерении a,Следуя идее этой публикации, мы можем добавить до a.ndim новых измерений более кратким способом, используя np.reshape следующим образом:

b = b.reshape((-1,) + (1,)*(a.ndim-1))
print(b.shape)
# (101, 1, 1, 1, 1, 1)

Теперьмы можем вычесть b из a в соответствии с требованиями:

a[..., 0, None] = a[..., 0, None] - b.reshape((-1,) + (1,) * (a.ndim-1))

И если мы проверим форму a:

print(a.shape)
# (101, 256, 1, 3, 1, 10)

Подробности

Вот некоторые пояснения по некоторым вопросам, которые могут возникнуть из предыдущего ответа.Давайте рассмотрим следующий более простой пример:

a = np.array([[1,2,3],[4,5,6]])
print(a)
array([[1, 2, 3],
       [4, 5, 6]])
print(a.shape)
# (2, 3)

b = np.array([1,1])[:,None]
array([[1],
       [1]])
print(b.shape)
# (2, 1)

Итак, для этого примера мы могли бы применить ту же логику, что и решение, приведенное выше:

a[:,0,None] = a[:,0,None] - b

array([[0, 2, 3],
       [3, 5, 6]])

, которая путем проверки полученного массива, какожидаемое b было вычтено из a по первому индексу вдоль его последней оси, поэтому первый столбец во всех строках.


Итак, первая точка,

Почему мы должны добавить новую ось в a для вычитания?

Необходимо добавить новую ось к a, учитывая форму b.Обратите внимание, что b - это двумерный массив array([[1],[1]]), поэтому, если бы вы вычли его непосредственно из a, вы получили бы:

a[..., 0] - b
array([[0, 3],
       [0, 3]])

Итак, здесь произошло то, чтоМассив меньшего размера, т. е. первый член, представляющий собой просто срез вида 1D из a, array([1, 4]), был передан по большому массиву, чтобы они имели совместимые формы.

Это не будетнеобходимо, если вместо формы b было (2,):

b = np.array([1,1])
a[:,0] - b
# array([0, 3])

Но из-за способа определения b в реальном решении он имеет то же количество измерений, что и a.Таким образом, чтобы получить правильный вывод, мы должны добавить новую ось к a:

a[:,0,None] - b
array([[0],
       [3]])

Таким образом, мы получим правильный вывод.


При описанном выше способе невозможно присвоить разницу новому массиву, выступающему в качестве «исправленной копии»?

.Ответ на этот вопрос можно понять, взглянув на результат вычитания:

c = a[:,0,None] - b
c.shape
(2, 1)

Итак, здесь a[:,0,None] - это то, что называется «разрезанным представлением» a.Поэтому обратите внимание, что, присваивая этот результат c, вы сохраняете только фактические sliced wiew из a, а не все ndarray.Если вы хотите изменить a в тех же позициях фактического среза, вам нужно будет присвоить его тому же нарезанному представлению a, поэтому:

a[:,0,None] = a[:,0,None] - b
print(a.shape)
# (2, 3)

Теперь результат имеетожидаемый результат, так как мы изменили только срез a.Если вы хотите сохранить копию оригинала ndarray, вы можете использовать np.copy, которая будет возвращать фактическую копию, а не фрагмент a, а затем присваивать результат "исправленная копия ":

a_c = np.copy(a)
a_c[:,0,None] = a[:,0,None] - b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...