2015-09-01 1 views
2

У меня есть вложенное словарь произвольного уровня, который содержит имена полей в качестве ключей, а также 1-D Numpy массивы одного и того же размера, как и значения, например:NumPy структурированный массив из произвольности уровня вложенного словаря

d = {'a' : arr1, 'b' : {'b1' : arr2, 'b2' : {'c' : arr3}}} 

ли существует простой способ построить из него массив с числовым структурированным массивом, который отражает исходную иерархию? Кроме того, было бы полезно сохранить порядок имен полей, если дано OrderedDict. Обычно функции np.array, np.asarray, np.rec.array не помогают.

+0

Сделайте 'arr1',' arr2' и 'arr3' все имеют одинаковые размеры? –

+0

Да, спасибо, это важный аспект, исправленный –

+0

Я все еще не совсем понимаю, что вы пытаетесь сделать. В каком смысле иерархия данных, если каждый элемент в 'arr1' имеет соответствующий элемент в' arr2' и 'arr3'? Как вы хотите использовать массив? –

ответ

2

Обычно это можно сделать в 2 этапа. Создайте составной тип dtype, соответствующий макету словаря. Затем заполните пустой массив массивами из словаря.

Построить словарь образца:

In [94]: arr1=np.arange(10) 
In [95]: arr2=np.arange(100.,110.) 
In [96]: arr3=np.arange(200,210) 
In [98]: d={'a':arr1, 'b':{'b1':arr2, 'b2':{'c':arr3}}} 

Эта функция конструирует DTYPE:

def mkdt(d): 
    ll = [] 
    for k,v in d.items(): 
     if isinstance(v,np.ndarray): 
      ll.append((k,v.dtype)) 
     else: 
      ll.append((k,mkdt(v))) 
    return ll 

In [176]: np.dtype(foo(d)) 
Out[176]: dtype([('a', '<i4'), ('b', [('b1', '<f8'), ('b2', [('c', '<i4')])])]) 

Эта функция значений копирует данные из d к A:

def copy_values(d, A): 
    if A.dtype.names: 
     for n in A.dtype.names: 
      copy_values(d[n], A[n]) 
    else: 
     A[:]=d 

In [264]: A=np.zeros(d['a'].shape,dt)  
In [265]: copy_values(d,A) 
In [266]: A 
Out[266]: 
array([(0, (100.0, (200,))), (1, (101.0, (201,))), (2, (102.0, (202,))), 
     (3, (103.0, (203,))), (4, (104.0, (204,))), (5, (105.0, (205,))), 
     (6, (106.0, (206,))), (7, (107.0, (207,))), (8, (108.0, (208,))), 
     (9, (109.0, (209,)))], 
     dtype=[('a', '<i4'), ('b', [('b1', '<f8'), ('b2', [('c', '<i4')])])]) 

(ранее решение)

Это интерактивный сеанс (ipython), который передает данные из словаря, подобного вашему, в структурированный массив.

In [94]: arr1=np.arange(10) 
In [95]: arr2=np.arange(100,110) 
In [96]: arr3=np.arange(200,210) 
In [98]: d={'a':arr1, 'b':{'b1':arr2, 'b2':{'c':arr3}}} 

Соответствующие dtype :.

In [100]: dt=np.dtype([('a','i'), ('b', np.dtype([('b1','i'),('b2',np.dtype([('c','i')]))]))]) 

Сделать пустой массив нужного размера и типа, и заполнить поля

In [102]: A=np.zeros((10,),dt)  
In [104]: A['a']=d['a'] 
In [105]: A['b']['b1']=d['b']['b1'] 
In [106]: A['b']['b2']['c']=d['b']['b2']['c'] 

In [107]: A 
Out[107]: 
array([(0, (100, (200,))), (1, (101, (201,))), (2, (102, (202,))), 
     (3, (103, (203,))), (4, (104, (204,))), (5, (105, (205,))), 
     (6, (106, (206,))), (7, (107, (207,))), (8, (108, (208,))), 
     (9, (109, (209,)))], 
     dtype=[('a', '<i4'), ('b', [('b1', '<i4'), ('b2', [('c', '<i4')])])]) 

Если все поля одинаковы DTYPE (здесь целое), этот массив также может быть построен как вид на 2d массива:

np.column_stack([arr1,arr2,arr3]).view(dt).ravel() 

Это работает, потому что (10,3) массив имеет тот же формат буфера данных в виде структурированного массива.


from numpy.lib import recfunctions 

дает доступ к некоторым функциям полезности.

recfunctions.recursive_fill_fields, например, может скопировать данные из A в другой массив того же DTYPE (но не из column_stack. Он использует рекурсию для обработки вложенного DTYPE.

In [149]: recfunctions.flatten_descr(dt) 
Out[149]: (('a', dtype('int32')), ('b1', dtype('int32')), ('c', dtype('int32'))) 

сглаживает ваш вложенности.

In [150]: recfunctions.get_fieldstructure(dt) 
Out[150]: {'a': [], 'b': [], 'b1': ['b'], 'b2': ['b'], 'c': ['b', 'b2']} 

Как эти функции обрабатывают сложные типы данных, могут быть более полезными, чем то, что они на самом деле делают. Посмотрите на код.

+0

спасибо, хорошо работает :) расширил его с получением размера массива во время выполнения –

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