Между shapes () и (1,), почему я могу выполнять регулярные, но не на месте операции?

#python #numpy #array-broadcasting #in-place

#python #numpy #трансляция массива #на месте

Вопрос:

Когда я пытаюсь передать на месте из shape (1,) в shape () , возникает numpy ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,) . Я понимаю, что операторы inplace предназначены для работы с тем же фрагментом памяти, что и входные данные, поэтому вы не могли, скажем, транслировать на месте из shape (5,) в shape (1,) . Но в случае shape (1,) (или любого массива размером 1) размер совпадает со скаляром с shape () . Тогда почему я не могу не выполнять операцию на месте a = b , где a имеет форму () и b имеет форму (1,) ? Работает обратное.

Код:

 a = np.array(0)
b = np.array([0])
a   b  # valid
b  = a  # valid
a  = b  # ValueError
  

Результат:

 ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,)
  

Комментарии:

1. При работе с массивом с shape не учитывается особый случай (1,) , когда вы просто не можете преобразовать одномерный массив в нулевой размерный. Однако в этом случае вы могли бы использовать a = b.squeeze() , что, вероятно, более уместно. Противоположное работает, потому что вы можете преобразовать нулевой размерный ndarray в любую форму.

2. a[()] является единственным допустимым индексом для a .

Ответ №1:

Хотя мы можем получить некоторые идеи из тестирования, это может сводиться к деталям реализации (в скомпилированном коде).

 In [81]: a = np.array(0); b = np.array([0])
In [82]: a,b
Out[82]: (array(0), array([0]))
  

Сумма двух создает массив (1,) . Это согласуется с правилами трансляции. a передается в (1,), а затем суммируется.

 In [83]: a b
Out[83]: array([0])
  

Мы можем добавить () или скалярный:

 In [84]: a  = a
  

но ваш случай ошибки, по-видимому, пытается поместить эту (1,) сумму в () цель:

 In [85]: a  = b
Traceback (most recent call last):
  File "<ipython-input-85-294cacd62d6f>", line 1, in <module>
    a  = b
ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,)
  

С правильным индексом можно присвоить значение a :

 In [86]: a[:] = 1
Traceback (most recent call last):
  File "<ipython-input-86-aa15caba710a>", line 1, in <module>
    a[:] = 1
IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed

In [87]: a[()] =2
In [88]: a
Out[88]: array(2)
In [89]: a[...] = a b
In [90]: a
Out[90]: array(2)
  

Но, по-видимому = , тип присваивания использует этот более обобщенный подход к присвоению.

Мы также не можем = преобразовать (1,1) в (1,):

 In [92]: b  = np.array([[1]])
Traceback (most recent call last):
  File "<ipython-input-92-15b525996e5d>", line 1, in <module>
    b  = np.array([[1]])
ValueError: non-broadcastable output operand with shape (1,) doesn't match the broadcast shape (1,1)
  

Очевидно = , что такое назначение не может уменьшить числовые размеры.

В качестве примечания, можно передать массив (1,) в массив (0,)

 In [100]: c = np.zeros((0,))
In [101]: c  = b
In [102]: c
Out[102]: array([], dtype=float64)
  

То есть на 2-м этапе трансляции (после сопоставления количества измерений) он может уменьшить размер 1 измерения до 0. Но это отличается от изменения количества измерений с n 1 на n .