Почему numpy.ravel возвращает копию?

В следующем примере:

>>> import numpy as np
>>> a = np.arange(10)
>>> b = a[:,np.newaxis]
>>> c = b.ravel()
>>> np.may_share_memory(a,c)
False

Почему numpy.ravel возвращает копию моего массива? Не нужно ли возвращать a?

Edit:

Я только что обнаружил, что np.squeeze не возвращает копию.

>>> b = a[:,np.newaxis]
>>> c = b.squeeze()
>>> np.may_share_memory(a,c)
True

Почему существует разница между squeeze и ravel в этом случае?

Edit:

Как указано в mgilson, newaxis отмечает массив как несменяемый, поэтому ravel возвращает копию.

Итак, новый вопрос заключается в том, почему newaxis помещает массив как несмежный.

История становится еще более странной:

>>> a = np.arange(10)
>>> b = np.expand_dims(a,axis=1)
>>> b.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> c = b.ravel()
>>> np.may_share_memory(a,c)
True

В соответствии с документацией для expand_dims она должна быть эквивалентна newaxis.

Ответ 1

Это может быть не лучший ответ на ваш вопрос, но похоже, что вставка newaxis вызывает numpy для просмотра массива как несмежного - возможно, для целей вещания:

>>> a=np.arange(10)
>>> b=a[:,None]
>>> a.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> b.flags
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

Однако изменение не приведет к такому:

>>> c=a.reshape(10,1) 
>>> c.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

И эти массивы разделяют одну и ту же память:

>>> np.may_share_memory(c.ravel(),a)
True

ИЗМЕНИТЬ

np.expand_dims фактически реализуется с использованием reshape, поэтому он работает (это небольшая ошибка в документации, я полагаю). Здесь источник (без docstring):

def expand_dims(a,axis):
    a = asarray(a)
    shape = a.shape
    if axis < 0:
        axis = axis + len(shape) + 1
    return a.reshape(shape[:axis] + (1,) + shape[axis:])

Ответ 2

Похоже, что это может быть связано с шагами:

>>> c = np.expand_dims(a, axis=1)
>>> c.strides
(8, 8)

>>> b = a[:, None]
>>> b.strides
(8, 0)
>>> b.flags
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> b.strides = (8, 8)
>>> b.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

Я не уверен, какую разницу может сделать шаг по размеру 1, но похоже, что создание numpy относится к массиву как к непрерывному.