2016-03-04 1 views
3

tl; dr Могу ли я изменить вид массива numpy от 5x5x5x3x3x3 до 125x1x1x3x3x3 без использования numpy.resape?Изменение формы n-мерного массива без использования reshape

Я хотел бы выполнить операцию раздвижного окна (с разными шагами) на том (размер MxMxM). Массив скользящего окна может быть сгенерирован с использованием numpy.lib.stride_tricks.as_strided, как ранее было предложено Benjamin и Eickenberg, и продемонстрировано в приведенном ниже фрагменте кода, который использует helper method from skimage, который использует as_strided.

Выход из этого вспомогательного метода дает мне форму NxNxNxnxnxn, но я бы предпочел, чтобы форма была N^3x1xnxnxn. Хотя я могу использовать np.reshape для достижения этого, np.resape медленный, если объем становится большим (> 100x100x100), что я не уверен, почему. Я думал, что могу использовать as_stride для изменения вывода, но с ошибками numpy (фрагмент кода ниже). Любые идеи о том, как я могу получить представление о выходе из вспомогательного метода как N ** 3x1xnxnxn без использования np.reshape?

import numpy as np 
import skimage 
l = 15 
s = 3 
X = np.ones((l,l,l))  
print('actual shape',X.shape) 
view = skimage.util.shape.view_as_blocks(X,(s,s,s))  
print('original view',view.shape) 

new_shape = ((l/s)**3,1,1,s,s,s) 
print('new view',new_shape)  

view_correct = view.reshape(new_shape) 
print(view_correct.shape) 
print('coord:','124,0,0,2,2,2','value:',view_correct[124,0,0,2,2,2]) 

view_incorrect = np.lib.stride_tricks.as_strided(view, shape=new_shape) 
print(view_incorrect.shape) 
print('coord:','124,0,0,2,2,2','value:',view_incorrect[124,0,0,2,2,2]) 
+1

'view_as_blocks' использует' as_strided' с соответствующими 'strides' и' shape' для создания нового представления. И затем вы снова применяете 'as_strided', с другой' shape' (и другой 'ndim'), без изменения' strides'. Не следует ли применять 'as_strided' непосредственно к' X' - с правильными 'шагами' и' shape'? – hpaulj

ответ

1

Я взял пример из view_as_blocks, и попробовал ваш стиль RESHAPE:

A = np.arange(4*4).reshape(4,4) 
B = view_as_blocks(A, block_shape=(2, 2)) 
print(A.__array_interface__) 
print(B.__array_interface__) 

C = B.reshape((2*2,2,2)) 
print(C.__array_interface__) 

производства:

{'typestr': '<i4', 'data': (153226600, False), 'shape': (4, 4), 
'descr': [('', '<i4')], 'version': 3, 'strides': None} 
{'typestr': '<i4', 'data': (153226600, False), 'shape': (2, 2, 2, 2), 
'descr': [('', '<i4')], 'version': 3, 'strides': (32, 8, 16, 4)} 
{'typestr': '<i4', 'data': (150895960, False), 'shape': (4, 2, 2), 
'descr': [('', '<i4')], 'version': 3, 'strides': None} 

data указатель на A и B то же самое; B - вид на A.

Но указатель на C отличается. Это копия. Это объясняет, почему в вашем случае так много времени.


Позволяет сделать немного по-другому:

A = np.arange(4*4).reshape(4,4) 
B = view_as_blocks(A, block_shape=(2, 2)) 
print(A.__array_interface__) 
print(B.__array_interface__) 

C = B.reshape((2*2,1,2,2)) 
print(C.__array_interface__) 

D = as_strided(B, shape=(2*2,1,2,2)) 
print(D.__array_interface__) 

print(B[1,1,:,:]) 
print(C[3,0,:,:]) 
print(D[3,0,:,:]) 

производства

1254:~/mypy$ python3 skshape.py 
{'strides': None, 'typestr': '<i4', 'version': 3, 
'data': (154278744, False), 'shape': (4, 4), 'descr': [('', '<i4')]} 
{'strides': (32, 8, 16, 4), 'typestr': '<i4', 'version': 3, 
'data': (154278744, False), 'shape': (2, 2, 2, 2), 'descr': [('', '<i4')]} 
{'strides': None, 'typestr': '<i4', 'version': 3, 
'data': (155705400, False), 'shape': (4, 1, 2, 2), 'descr': [('', '<i4')]} 
{'strides': (32, 8, 16, 4), 'typestr': '<i4', 'version': 3, 
'data': (154278744, False), 'shape': (4, 1, 2, 2), 'descr': [('', '<i4')]} 

[[10 11] 
[14 15]] 
[[10 11] 
[14 15]] 
[[ 154561960 -1217783696] 
[   48  3905]] 

Опять Reshape создает копию. Второй as_strides возвращает вид, но шагающий завинчивается. Он смотрит на память за пределами исходного буфера данных (это часть того, почему игра с шагами сама по себе опасна).


В моем примере, обратите внимание на первом повороте значение каждого блока

print(B[:,:,0,0]) 
print(C[:,0,0,0]) 

[[ 0 2] 
[ 8 10]] 
[ 0 2 8 10] 

Для B, строки увеличивают на 8, столбцы 2; это отражено в шаге (32,8) (4 * 8,4 * 2).

Но в C шаги (2,6,2) - шаг не может этого сделать.

Из этого я заключаю, что изменение невозможно без копирования.

+0

hpaulj, благодарю вас за подробное объяснение. использование __ array_interface__ было действительно полезно, помогая мне понять проблему. – teng