ravel
возвращает копию, а не представление
Из numpy.ravel
документов :
Возвращается одномерный массив, содержащий элементы ввода. Копия производится только при необходимости.
Так что, по сути, когда вы рассказываете о транспонировании, на самом деле нужна копия. Вы изменяете значение в копии, поэтому оно не отражается в исходном массиве.
Проверка, является ли возвращенный массив представлением или копией
В таком простом случае, как этот, вы можете проверить, является ли массив b
представлением a
или нет, сравнив идентичность b.base
и a
:
a = np.array([[1,2,3], [4,5,6]])
b = a.T
c = b.ravel()
print('b is a view of a\n%s\n' % (b.base is a))
print('c is a view of a\n%s\n' % (c.base is a))
Выход:
b is a view of a
True
c is a view of a
False
Почему a.T.ravel()
возвращает копию?
Shocker: на самом деле есть способ заставить a.T.ravel()
возвращать представление вместо копии. Вы можете сделать это, явно установив order='F'
(то есть порядок Fortran):
a = np.array([[1,2,3], [4,5,6]])
c = a.T.ravel()
d = a.T.ravel(order='F')
print('d is a view of a\n%s\n' % (d.base is a))
Выход:
d is a view of a
True
Однако, изменение значения order
kwarg изменит порядок (кажется) значений в массиве raveled:
print('c\n%s\n' % c)
print('d\n%s\n' % d)
Выход:
c
[1 4 2 5 3 6]
d
[1 2 3 4 5 6]
Чтобы понять, почему изменение order
приводит к возвращению представления, мы можем взглянуть на код самой функции ravel
. Реализация np.ndarray.ravel
- это , похороненная в слое C . Читая об этом источник, становится ясно, что для возврата вида из ravel
должны быть выполнены два условия:
Входной массив должен быть смежным.
Порядок непрерывного входного массива должен соответствовать порядку order
kwarg, переданного в ravel
.
Кварг имеет значение по умолчанию order='C'
. Таким образом, по умолчанию ravel
будет возвращать представление только в том случае, если вы запускаете его в C-смежном массиве. В большинстве случаев, когда вы инициализируете новый массив Numpy a
, он будет начинаться как C-смежный. Однако транспонирование a.T
будет F-смежным. Вы можете увидеть это в действии в своем коде, проверив .flags
свойство ваших массивов:
a = np.array([[1,2,3], [4,5,6]])
print('the flags of a\n%s\n' % a.flags)
print('the flags of a.T\n%s\n' % a.T.flags)
Выход:
the flags of a
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
the flags of a.T
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : False
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
Что, черт возьми, означают С- и F-смежные?
Есть большая вероятность, что термины C-смежный и F-смежный кажутся вам бредом. Их объяснение потребовало бы совершенно другого вопроса, который, к счастью, кто-то из SO уже задал. Вот ссылка на старый ответ , который дает действительно интуитивно понятный обзор того, что на самом деле означает порядок C и F.
Протест
В вашем реальном коде я бы не слишком беспокоился о том, является ли ravel
возвращаемыми представлениями или копиями. В действительности вы не всегда получаете повышение производительности, гарантируя использование представлений. Избегайте преждевременной оптимизации в целом.