将任何字典转换为结构化数组



我正在尝试生成一个结构化numpy数组,该数组从字典中获取字段名称和变量类型。我希望它能够处理用户可以扔给它的大多数内容。

目前它的工作原理是这样的:

>>> d = dict( a=0.456, b=1234.5687020, c=4, d=np.arange(3), text='text')
>>> dtype = [(str(key), val.__class__) for key, val in d.iteritems()]     
>>> arr = np.zeros( (5,), dtype=dtype)
>>> arr
array([(0.0, '', 0, 0.0, 0), (0.0, '', 0, 0.0, 0), (0.0, '', 0, 0.0, 0),
(0.0, '', 0, 0.0, 0), (0.0, '', 0, 0.0, 0)], 
dtype=[('a', '<f8'), ('text', 'S'), ('c', '<i8'), ('b', '<f8'), ('d', 'O')])

目前为止,一切都好。但是我现在尝试将示例字典的内容分配给第一个元素,这并不全是好的:

>>> for key, val in d.iteritems():
...     arr[0][str(key)] = val
>>> arr[0]
(0.456, '', 4, 1234.5687020, [0, 1, 2])

数字和数组看起来没问题,但缺少文本。有趣的是,手动分配给文本字段会产生不同的结果:

>>> arr[0]['text'] = 'text'
>>> arr[0]['text'] 
't'

我觉得这很难理解...

我确定类型的方法似乎选择了过于严格的类型。我预计使用 float32 初始化然后分配 float64 之类的事情会减少数据丢失,但我至少希望数组能够保存示例数据。

有没有一种更强大(甚至可能更优雅?)的方法来确定dtype允许字符串正常工作?

我寻找的是一种确定字典内容类型的稳健方法。如果我需要要求输入字典中的文本定义最大字符串长度,这是可以接受的,但我的函数事先不知道它将获得哪些键和类型。

您需要为类型提供长度S

dtype = [('a', float), ('b', float), ('c', int), ('d', numpy.ndarray), ('text', 'S10')]
arr = np.zeros( (5,), dtype=dtype)
for key, val in d.items():
arr[0][str(key)] = val

现在:

>>> arr[0]
( 0.456,  1234.56870202, 4, array([0, 1, 2]), b'text')

我设法想出的最好的"自动解决方案是使用由每个元素组成的 np 数组dtype,而不是__class__属性:

>>> dtype = [(str(key), np.array([val]).dtype) for key, val in d.iteritems()]
>>> dtype
[('a', dtype('float64')), ('text', dtype('S4')), ('c', dtype('int64')), ('b', dtype('float64')), ('d', dtype('int64'))]
>>> arr = np.zeros( (5,), dtype=dtype)
>>> for key, val in d.iteritems():
...     arr[0][str(key)] = val
... 
>>> arr[0]
(0.456, 'text', 4, 1234.568702020934, 0)

这会将文本输入限制为示例数据中包含的长度,如果任何输入是 numpy 数组,则会失败(如上所示 - 它将数组分类为int,因为这就是它的元素)。

我最终所做的是编译一个包含所有字符串元素的单独列表,然后手动将它们添加到 dtype 中,如'S128'

>>> stringkeys = [ str(key) for key, val in d.iteritems() if 'str' in str(val.__class__)]
>>> dtype = [(str(key), val.__class__) for key, val in d.iteritems() if not 'str' in str(val.__class__)] + [(key, 'S128') for key in stringkeys]
>>> dtype
[('a', <type 'float'>), ('c', <type 'int'>), ('b', <type 'float'>), ('d', <type 'numpy.ndarray'>), ('text', 'S128')]

不那么优雅,我想还有其他一些类型,我可能会手动捕获,但至少它可以工作。

我真的希望有一个表达式可以自动生成一个可以正常工作的类型。而且我仍然不明白为什么上面的循环甚至根本不分配字符串变量,尽管直接赋值确实分配了一些东西......

最新更新