Вы действительно могли бы сделать это, воспользовавшись вещанием .
Давайте начнем с генерации некоторой случайной 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