我正在尝试生成一个结构化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')]
不那么优雅,我想还有其他一些类型,我可能会手动捕获,但至少它可以工作。
我真的希望有一个表达式可以自动生成一个可以正常工作的类型。而且我仍然不明白为什么上面的循环甚至根本不分配字符串变量,尽管直接赋值确实分配了一些东西......