Обычно это можно сделать в 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']}
Как эти функции обрабатывают сложные типы данных, могут быть более полезными, чем то, что они на самом деле делают. Посмотрите на код.
Сделайте 'arr1',' arr2' и 'arr3' все имеют одинаковые размеры? –
Да, спасибо, это важный аспект, исправленный –
Я все еще не совсем понимаю, что вы пытаетесь сделать. В каком смысле иерархия данных, если каждый элемент в 'arr1' имеет соответствующий элемент в' arr2' и 'arr3'? Как вы хотите использовать массив? –