2015-02-14 2 views
4

Я знаю, что я могу сделать следующее:Numpy - Stacked вид памяти двух 1D массивов

import numpy as np 
c = np.random.randn(20, 2) 
a = c[:, 0] 
b = c[:, 1] 

Здесь a и b являются указателями на c «s первого и второго столбца соответственно. Изменение a или b изменится на c (то же самое взаимно).

Однако я хочу достичь именно противоположного. Я хочу создать представление 2D-памяти, в котором каждый столбец (или строка) будет указывать на память другого 1D-массива. Предположим, что у меня уже есть два массива 1D, возможно ли создать 2D-представление для этих массивов, где каждая строка/столбец указывает на каждый из них?

Я могу создать c из a и b следующим образом:

c = np.c_[a, b] 

Однако это копии a «s и b памяти на c. Могу ли я как-то создать c как «вид» [a b], где, изменяя элемент c, это отражает в соответствующем массиве или b 1D?

ответ

4

Я не думаю, что это возможно.

В первом примере, значение взглядов a и b переплетены, как можно видеть из этой вариации:

In [51]: c=np.arange(10).reshape(5,2) 
In [52]: a, b = c[:,0], c[:,1] 
In [53]: a 
Out[53]: array([0, 2, 4, 6, 8]) 
In [54]: c.flatten() 
Out[54]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

data буфера для c и a начали в той же точке памяти; b начинается с 4 байтов в этот буфер.

In [55]: c.__array_interface__ 
Out[55]: 
{'strides': None, 
'data': (172552624, False),...} 

In [56]: a.__array_interface__ 
Out[56]: 
{'strides': (8,), 
'data': (172552624, False),...} 

In [57]: b.__array_interface__ 
Out[57]: 
{'strides': (8,), 
'data': (172552628, False),...} 

Даже если a,b сплит были рядами, b бы начать просто дальше в том же общий буфер данных.

Из .flags мы видим, что c - C-contiguous, b - нет. Но значения b доступны с постоянными шагами в этом общем буфере данных.

Когда a и b создаются отдельно, их буферы данных полностью разделены. Механизм шага numpy не может перемещаться между этими двумя буферами данных. 2d-композиция a и b должна работать со своим собственным буфером данных.

Я могу представить, как писать класс, который выглядит так, как вы хотите. Файл indexing_tricks, который определяет np.c_, может дать вам идеи (например, класс с пользовательским методом __getitem__). Но у него не было бы скоростных преимуществ обычного 2d-массива. И может быть сложно реализовать всю функциональность ndarray.

+0

Большое спасибо за информацию! –

2

Хотя ответ @ hpaulj является правильным, для вашего конкретного случая и более как упражнение в понимании макета памяти numpy, чем что-либо с практическими приложениями, вот как вы можете получить представление о двух массивах с 1-D в виде столбцов общего массив:

>>> from numpy.lib.stride_tricks import as_strided 
>>> a = np.arange(10) 
>>> b = np.arange(20, 30) 
>>> col_stride = (b.__array_interface__['data'][0] - 
        a.__array_interface__['data'][0]) 
>>> c = as_strided(a, shape=(10, 2), strides=(a.strides[0], col_stride)) 
>>> c 
array([[ 0, 20], 
     [ 1, 21], 
     [ 2, 22], 
     [ 3, 23], 
     [ 4, 24], 
     [ 5, 25], 
     [ 6, 26], 
     [ 7, 27], 
     [ 8, 28], 
     [ 9, 29]]) 
>>> c[4, 1] = 0 
>>> c[6, 0] = 0 
>>> a 
array([0, 1, 2, 3, 4, 5, 0, 7, 8, 9]) 
>>> b 
array([20, 21, 22, 23, 0, 25, 26, 27, 28, 29]) 

Есть много вещей, которые могут пойти не так здесь, в основном, что массив b не имел его счетчик ссылок увеличивается, так что если вы удалите его его память будет выпущена, но вид будет все еще доступ к нему. Он также не может быть расширен до более чем двух одномерных массивов и требует, чтобы оба одномерных массива имели один и тот же шаг.

Конечно, только потому, что вы можете это сделать, это не значит, что вы должны это сделать! И вы определенно не должны этого делать.

+0

Благодарим вас за пример. Я понимаю, что это не идеально, но я думаю, что он может работать в «контролируемой» среде (например, классе), когда вы можете гарантировать существование 'b'. В любом случае, спасибо вам за объяснения. –