2016-11-18 2 views
1

У меня есть следующий Numpy структурированный массив:Вид Numpy структурированного массива со смещением

In [250]: x 
Out[250]: 
array([(22, 2, -1000000000, 2000), (22, 2, 400, 2000), 
     (22, 2, 804846, 2000), (44, 2, 800, 4000), (55, 5, 900, 5000), 
     (55, 5, 1000, 5000), (55, 5, 8900, 5000), (55, 5, 11400, 5000), 
     (33, 3, 14500, 3000), (33, 3, 40550, 3000), (33, 3, 40990, 3000), 
     (33, 3, 44400, 3000)], 
     dtype=[('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4')]) 

Массив ниже является подмножеством (также вид) указанного массива:

Я пытаясь преобразовать y в обычный массив numpy. Я хочу, чтобы массив был представлением. Вопрос заключается в том, что следующее дает мне ошибку:

In [254]: y.view(('<i4',2)) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-254-88440f106a89> in <module>() 
----> 1 y.view(('<i4',2)) 

C:\numpy\core\_internal.pyc in _view_is_safe(oldtype, newtype) 
    499 
    500  # raises if there is a problem 
--> 501  _check_field_overlap(new_fieldtile, old_fieldtile) 
    502 
    503 # Given a string containing a PEP 3118 format specifier, 

C:\numpy\core\_internal.pyc in _check_field_overlap(new_fields, old_fields) 
    402   old_bytes.update(set(range(off, off+tp.itemsize))) 
    403  if new_bytes.difference(old_bytes): 
--> 404   raise TypeError("view would access data parent array doesn't own") 
    405 
    406  #next check that we do not interpret non-Objects as Objects, and vv 

TypeError: view would access data parent array doesn't own 

Однако, если я выбираю последовательных полей он работает:

In [255]: fields=['f1','f2'] 
    ...: 
    ...: y=x.getfield(np.dtype(
    ...:     {name: x.dtype.fields[name] for name in fields} 
    ...:     )) 
    ...: 

In [256]: y 
Out[256]: 
array([(22, 2), (22, 2), (22, 2), (44, 2), (55, 5), (55, 5), (55, 5), 
     (55, 5), (33, 3), (33, 3), (33, 3), (33, 3)], 
     dtype=[('f1', '<i4'), ('f2', '<i4')]) 

In [257]: y.view(('<i4',2)) 
Out[257]: 
array([[22, 2], 
     [22, 2], 
     [22, 2], 
     [44, 2], 
     [55, 5], 
     [55, 5], 
     [55, 5], 
     [55, 5], 
     [33, 3], 
     [33, 3], 
     [33, 3], 
     [33, 3]]) 

Посмотреть отливка, кажется, не работает, когда поля не являются смежными, есть альтернатива?

ответ

2

Да, используйте ndarray конструктор непосредственно:

x = np.array([(22, 2, -1000000000, 2000), 
       (22, 2,   400, 2000), 
       (22, 2,  804846, 2000), 
       (44, 2,   800, 4000), 
       (55, 5,   900, 5000), 
       (55, 5,  1000, 5000)], 
      dtype=[('f1','i'),('f2','i'),('f3','i'),('f4','i')]) 

fields = ['f4', 'f1'] 
shape = x.shape + (len(fields),) 
offsets = [x.dtype.fields[name][1] for name in fields] 
assert not any(np.diff(offsets, n=2)) 
strides = x.strides + (offsets[1] - offsets[0],) 
y = np.ndarray(shape=shape, dtype='i', buffer=x, 
       offset=offsets[0], strides=strides) 
print repr(y) 

Выдает:

array([[2000, 22], 
     [2000, 22], 
     [2000, 22], 
     [4000, 44], 
     [5000, 55], 
     [5000, 55]]) 

Btw, когда все поля в исходном массиве имеют тот же DTYPE, это гораздо проще, первый создайте представление для этого массива, за которым следует операция разрезания. Для того же результата, что и выше:

y = x.view('i').reshape(x.shape + (-1,))[:,-1::-3] 
+0

Удивительный! Благодарю. – snowleopard

+0

Должны ли поля работать непрерывно, чтобы это работало? ['f4', 'f1'] по-прежнему остается неизменным. Вот почему утверждение есть. – snowleopard

+0

Попробуйте 'fields = ['f4', 'f3', 'f1']'. смещения являются '[12, 8, 0]' - есть пробел -4 и -8. 'strides' не может справиться с обоими. – hpaulj

1

Следующие несколько запутывают - но суть в том, что для этого вида view для работы он должен иметь доступ к полям с регулярными шагами и формами массива. Получение представления из ['f1', 'f3'] завершается по той же причине, что и np.ones((12,4))[:,[0,2]].

========

В вашем структурированном массиве, каждая запись хранится как 4 * 'i4' байт. Это макет совместим с (п, 4) 'i4' массива:

In [381]: x.__array_interface__['data'] # databuffer pointer 
Out[381]: (160925352, False) 
In [382]: x.view(('i',4)).__array_interface__['data'] 
Out[382]: (160925352, False)   # same buffer 
In [387]: x.view(('i',4)).shape 
Out[387]: (12, 4) 

, но когда я беру различные кусочки этого массива

In [383]: x.view(('i',4))[:,[0,1]].__array_interface__['data'] 
Out[383]: (169894184, False)  # advance indexing - a copy 

In [384]: x.view(('i',4))[:,:2].__array_interface__['data'] 
Out[384]: (160925352, False)  # same buffer 

Но выбор [ 'f1', 'f3'] эквивалентно: x.view(('i',4))[:,[0,2]], другой экземпляр.

Или посмотрите на шаги. С 1-го 2-х полей

In [404]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f1','f2']})) 
In [405]: y2.dtype 
Out[405]: dtype([('f1', '<i4'), ('f2', '<i4')]) 
In [406]: y2.strides 
Out[406]: (16,) 
In [407]: y2.view(('i',2)).strides 
Out[407]: (16, 4) 

Чтобы увидеть этот массив, как только Интс, он может уйти от 16 для строк, и 4 к шагу колонн и просто взять 2 колонки.

Или посмотреть на полный словарь для 4 колонки и 2 колонки случаев

In [409]: x.view(('i',4)).__array_interface__ 
Out[409]: 
{'data': (160925352, False), 
'descr': [('', '<i4')], 
'shape': (12, 4), 
'strides': None, 
'typestr': '<i4', 
'version': 3} 
In [410]: y2.view(('i',2)).__array_interface__ 
Out[410]: 
{'data': (160925352, False), 
'descr': [('', '<i4')], 
'shape': (12, 2), 
'strides': (16, 4), 
'typestr': '<i4', 
'version': 3} 

же махов и DTYPE, просто разные формы. Случай y2 работает, потому что он может получить доступ к нужным байтам с шагами и игнорировать 2 столбца.

Если я нарежьте из 2 средних столбцов при 4 столбца, я получаю вид - тот же буфер данных, но со смещением:

In [385]: x.view(('i',4))[:,2:4].__array_interface__['data'] 
Out[385]: (160925360, False) 

, но с использованием getfield с этими 2 поля дает ту же ошибку, как с [ 'f1', 'f3']:

In [388]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f2','f3']})).view(('i',2)) 
... 
ValueError: new type not compatible with array. 

view не может осуществить это DataBuffer смещение, нарезка может.

========

Глядя снова на 2 средних полях:

In [412]: y2=x.getfield(np.dtype({name: x.dtype.fields[name] for name in ['f2','f3']})) 
    ...: 
In [413]: y2 
Out[413]: 
array([(2, -1000000000), (2, 400), (2, 804846), (2, 800), (5, 900), 
     (5, 1000), (5, 8900), (5, 11400), (3, 14500), (3, 40550), 
     (3, 40990), (3, 44400)], 
     dtype={'names':['f2','f3'], 'formats':['<i4','<i4'], 'offsets':[4,8], 'itemsize':12}) 
In [414]: y2.__array_interface__['data'] 
Out[414]: (160925352, False) 

y2 указывает на оригинальный старт базы данных. Он достигает смещения с смещениями dtype. Сравните это со смещением в In[385].

+0

Спасибо за очень подробный ответ, я ожидал, что процесс будет работать с непрерывными полями, но я также заметил, что он работает только с срезом, содержащим первое поле. Я понимаю, что если поля не являются непрерывными, запускается расширенная индексация, которая возвращает копию. Я не понимаю, почему он не работает с некоторыми сплошными полями, поскольку это, по-видимому, является срезом. – snowleopard

+0

Я добавил некоторую информацию о f2/f3 'slice'. Оба метода требуют какого-то смещения, но они используют разные методы. Один смещает указатель на databuffer и использует регулярный шаг оттуда. Другой использует смещения 'dtype' и исходный указатель на databuffer. – hpaulj

Смежные вопросы