从字典列表中创建NumPy记录数组的最简单方法?

问题描述 投票:10回答:3

说我有d = [dict(animal='cat', weight=5), dict(animal='dog', weight=20)]之类的数据(基本上是JSON,其中所有条目都具有一致的数据类型)。

在Pandas中,您可以使用df = pandas.DataFrame(d)将此表制成表–是否有可与普通NumPy记录数组媲美的东西? np.rec.fromrecords(d)似乎没有给我想要的东西。

python numpy
3个回答
6
投票

您可以创建一个具有正确大小和dtype的空结构化数组,然后从列表中填充它。

http://docs.scipy.org/doc/numpy/user/basics.rec.html

结构化数组可以按字段或逐行填充。...如果您逐行填写,则需要一个元组(而不是列表或数组!):

In [72]: dt=dtype([('weight',int),('animal','S10')])

In [73]: values = [tuple(each.values()) for each in d]

In [74]: values
Out[74]: [(5, 'cat'), (20, 'dog')]

dt中的字段以与values中相同的顺序出现。

In [75]: a=np.zeros((2,),dtype=dt)

In [76]: a[:]=[tuple(each.values()) for each in d]

In [77]: a
Out[77]: 
array([(5, 'cat'), (20, 'dog')], 
      dtype=[('weight', '<i4'), ('animal', 'S10')])

通过更多测试,我发现我可以直接从values创建数组。

In [83]: a = np.array(values, dtype=dt)

In [84]: a
Out[84]: 
array([(5, 'cat'), (20, 'dog')], 
      dtype=[('weight', '<i4'), ('animal', 'S10')])

dtype可以从一个(或多个)词典项目中推导:

def gettype(v):
    if isinstance(v,int): return 'int'
    elif isinstance(v,float): return 'float'
    else:
        assert isinstance(v,str)
        return '|S%s'%(len(v)+10)
d0 = d[0]
names = d0.keys()
formats = [gettype(v) for v in d0.values()]
dt = np.dtype({'names':names, 'formats':formats})

生产中:

dtype=[('weight', '<i4'), ('animal', 'S13')]

4
投票

好吧,因为numpy不使用列标题,所以您可以使生活更加轻松,并且仅依赖于Pandas

Pandas

df = pandas.DataFrame(d)
numpyMatrix = df.as_matrix() #spits out a numpy matrix

或者您可以忽略Pandas并使用numpy + list comprehension将dicts分解为值并存储为矩阵

Numpy

numpMatrix = numpy.matrix([each.values() for each in d])

0
投票

我的建议(通常hpaulj's answer有所改进:]:

dicts = [dict(animal='cat', weight=5), dict(animal='dog', weight=20)]

创建od dtype对象:

dt_tuples = []
for key, value in dicts[0].items():
    if not isinstance(value, str):
        value_dtype = np.array([value]).dtype
    else:
        value_dtype = '|S{}'.format(max([len(d[key]) for d in dicts]))
    dt_tuples.append((key, value_dtype))
dt = np.dtype(dt_tuples)

如您所见,字符串处理存在问题-我们需要检查它的最大长度以定义dtype。如果您的字典中没有字符串值,或者您确定所有这些值的长度都完全相同,则可以跳过此附加条件。

如果您正在寻找单线,将是这样的:

dt = np.dtype([(k, np.array([v]).dtype if not isinstance(v, str) else '|S{}'.format(max([len(d[k]) for d in dicts]))) for k, v in dicts[0].items()])

(为了可读性最好还是打破它。

值列表:

values = [tuple(d[name] for name in dt.names) for d in dicts]

因为我们迭代了dt.names,所以我们确定值的顺序是正确的。

并且,最后,创建数组:

a = np.array(values, dtype=dt)

© www.soinside.com 2019 - 2024. All rights reserved.