Python字典转换为NumPy结构化数组

49

我有一个词典需要转换为NumPy结构化数组。我正在使用arcpy函数NumPyArraytoTable,所以NumPy结构化数组是唯一可行的数据格式。

根据这个主题:Writing to numpy array from dictionary和这个主题:How to convert Python dictionary object to numpy array

我尝试了以下代码:

result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}

names = ['id','data']
formats = ['f8','f8']
dtype = dict(names = names, formats=formats)
array=numpy.array([[key,val] for (key,val) in result.iteritems()],dtype)

但我不断收到 expected a readable buffer object 错误信息。

下面的方法可以解决问题,但这种做法很愚蠢,对于真实数据肯定行不通。我知道有更为优雅的方法,只是想不出来。

totable = numpy.array([[key,val] for (key,val) in result.iteritems()])
array=numpy.array([(totable[0,0],totable[0,1]),(totable[1,0],totable[1,1])],dtype)
5个回答

71
你可以使用np.array(list(result.items()), dtype=dtype):
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}

names = ['id','data']
formats = ['f8','f8']
dtype = dict(names = names, formats=formats)
array = np.array(list(result.items()), dtype=dtype)

print(repr(array))

产量
array([(0.0, 1.1181753789488595), (1.0, 0.5566080288678394),
       (2.0, 0.4718269778030734), (3.0, 0.48716683119447185), (4.0, 1.0),
       (5.0, 0.1395076201641266), (6.0, 0.20941558441558442)], 
      dtype=[('id', '<f8'), ('data', '<f8')])

如果您不想创建元组的中间列表list(result.items()),则可以使用np.fromiter代替:
在Python2中:
array = np.fromiter(result.iteritems(), dtype=dtype, count=len(result))

在Python3中:
array = np.fromiter(result.items(), dtype=dtype, count=len(result))

为什么使用列表 [key,val] 不起作用:

顺便提一句,你的尝试,

numpy.array([[key,val] for (key,val) in result.iteritems()],dtype)

离成功非常接近。如果你将列表[key, val]改为元组(key, val),那么它就能够正常工作了。当然,

numpy.array([(key,val) for (key,val) in result.iteritems()], dtype)

与之相同的东西是

numpy.array(result.items(), dtype)

在Python2中,或者

numpy.array(list(result.items()), dtype)

Python3 中的 np.array 对待列表与元组的方式不同:Robert Kern 解释说

一般来说,元组被视为“标量”记录,而列表是递归处理的。这个规则有助于 numpy.array() 弄清哪些序列是记录,哪些序列是其他要递归处理的序列;即哪些序列创建了另一个维度,哪些序列是原子元素。

由于 (0.0, 1.1181753789488595) 被视为其中的一个原子元素,所以它应该是一个元组,而不是一个列表。


我参考了你的这个答案来实现一些功能,但它没有起作用。我已经花了几天时间在这上面了。你能帮忙吗?http://stackoverflow.com/questions/32723802/scipy-and-preserving-mat-file-mat-matlab-data-file-structure - Raaj
1
直接复制粘贴代码示例会出错。我通过将result.items()更改为list(result.items())来修复它。Python 3.5 - Atlas7
2
@Atlas7:感谢您的提醒。已经更新了Python3的答案。 - unutbu

3

让我提出一种改进的方法,当字典的值是具有相同长度的列表时:

import numpy

def dctToNdarray (dd, szFormat = 'f8'):
    '''
    Convert a 'rectangular' dictionnary to numpy NdArray
    entry 
        dd : dictionnary (same len of list 
    retrun
        data : numpy NdArray 
    '''
    names = dd.keys()
    firstKey = dd.keys()[0]
    formats = [szFormat]*len(names)
    dtype = dict(names = names, formats=formats)
    values = [tuple(dd[k][0] for k in dd.keys())]
    data = numpy.array(values, dtype=dtype)
    for i in range(1,len(dd[firstKey])) :
        values = [tuple(dd[k][i] for k in dd.keys())]
        data_tmp = numpy.array(values, dtype=dtype)
        data = numpy.concatenate((data,data_tmp))
    return data

dd = {'a':[1,2.05,25.48],'b':[2,1.07,9],'c':[3,3.01,6.14]}
data = dctToNdarray(dd)
print data.dtype.names
print data

3

如果您接受使用pandas,那么就更加简单了:

import pandas
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}
df = pandas.DataFrame(result, index=[0])
print df

提供:

          0         1         2         3  4         5         6
0  1.118175  0.556608  0.471827  0.487167  1  0.139508  0.209416

2
我承认这是我的做法,通常而言,对于大量数据而言,DataFrames 比 np 数组更加高效。你应该添加:df = df.to_numpy().T - Catalina Chircu

2
我建议将键和值存储在不同的数组中,这通常更实用。数组结构是数组结构的完美替代品。由于大部分时间您只需要处理数据的一个子集(在这种情况下是键或值),因此仅使用其中一个数组进行操作比同时操作两个数组的一半更有效。
但如果无法使用此方法,我建议使用按列排序的数组,而不是按行排序的数组。这样,您将获得与使用两个数组相同的好处,但只打包在一个数组中。
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}

names = 0
values = 1
array = np.empty(shape=(2, len(result)), dtype=float)
array[names] = result.keys()
array[values] = result.values()

但我最喜欢的是这个(更简单):
import numpy as np
result = {0: 1.1181753789488595, 1: 0.5566080288678394, 2: 0.4718269778030734, 3: 0.48716683119447185, 4: 1.0, 5: 0.1395076201641266, 6: 0.20941558441558442}

arrays = {'names': np.array(result.keys(), dtype=float),
          'values': np.array(result.values(), dtype=float)}

1
请在发布代码之前进行测试。在您的第一个代码示例中,未指定 r,在第二个示例中未指定 k - NumesSanguis
如果值是复杂类型,比如浮点数数组,我们该如何在你的代码中定义这种类型? - Mnemosyne

1
与批准的答案类似。如果您想从字典键创建数组:
np.array( tuple(dict.keys()) )

如果您想从字典值创建一个数组:
np.array( tuple(dict.values()) )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接