Numpy: используйте reshape или newaxis для добавления размеров

или ndarray.reshape или numpy.newaxis можно использовать для добавления нового измерения в массив. Они оба, похоже, создают представление, есть ли причина или преимущество использовать один вместо другого?

>>> b
array([ 1.,  1.,  1.,  1.])
>>> c = b.reshape((1,4))
>>> c *= 2
>>> c
array([[ 2.,  2.,  2.,  2.]])
>>> c.shape
(1, 4)
>>> b
array([ 2.,  2.,  2.,  2.])
>>> d = b[np.newaxis,...]
>>> d
array([[ 2.,  2.,  2.,  2.]])
>>> d.shape
(1, 4)
>>> d *= 2
>>> b
array([ 4.,  4.,  4.,  4.])
>>> c
array([[ 4.,  4.,  4.,  4.]])
>>> d
array([[ 4.,  4.,  4.,  4.]])
>>> 

`

1 ответов


я не вижу большой разницы. Вы можете сделать тест времени на очень больших массивах. В основном оба играют с формой и, возможно, шагами. __array_interface__ это хороший способ доступа к этой информации. Например:

In [94]: b.__array_interface__
Out[94]: 
{'data': (162400368, False),
 'descr': [('', '<f8')],
 'shape': (5,),
 'strides': None,
 'typestr': '<f8',
 'version': 3}

In [95]: b[None,:].__array_interface__
Out[95]: 
{'data': (162400368, False),
 'descr': [('', '<f8')],
 'shape': (1, 5),
 'strides': (0, 8),
 'typestr': '<f8',
 'version': 3}

In [96]: b.reshape(1,5).__array_interface__
Out[96]: 
{'data': (162400368, False),
 'descr': [('', '<f8')],
 'shape': (1, 5),
 'strides': None,
 'typestr': '<f8',
 'version': 3}

оба создают представление, используя то же самое data буфер как оригинал. Та же форма, но reshape не изменяет strides. reshape позволяет указать order.

и .flags показывает различия в C_CONTIGUOUS флаг.

reshape может быть быстрее, потому что он вносит меньше изменений. Но в любом случае операция не должна сильно влиять на время больших вычислений.

, например, для больших b

In [123]: timeit np.outer(b.reshape(1,-1),b)
1 loops, best of 3: 288 ms per loop
In [124]: timeit np.outer(b[None,:],b)
1 loops, best of 3: 287 ms per loop

интересное наблюдение, что: b.reshape(1,4).strides -> (32, 8)

вот моя догадка. .__array_interface__ отображает базовый атрибут, и .strides больше похоже на свойство (хотя все это может быть похоронено в коде C). Базовое значение по умолчанию None, и при необходимости для расчета (или отображения с .strides) он вычисляет его из формы и размер товара. 32 - расстояние до конца 1-й строки (4x8). np.ones((2,4)).strides имеет одно и то же (32,8)None на __array_interface__.

b[None,:] С другой стороны готовится массив для вещания. При трансляции существующие значения используются повторно. Вот что такое 0 на (0,8) делает.

In [147]: b1=np.broadcast_arrays(b,np.zeros((2,1)))[0]

In [148]: b1.shape
Out[148]: (2, 5000)

In [149]: b1.strides
Out[149]: (0, 8)

In [150]: b1.__array_interface__
Out[150]: 
{'data': (3023336880L, False),
 'descr': [('', '<f8')],
 'shape': (2, 5),
 'strides': (0, 8),
 'typestr': '<f8',
 'version': 3}

b1 отображает же np.ones((2,5)) но есть только 5 пунктов.

np.broadcast_arrays - это функция, в /numpy/lib/stride_tricks.py. Он использует as_strided из того же файла. Эти функции непосредственно играют с атрибутами shape и strides.