从字典创建NumPy数组的最佳方法?

时间:2009-03-02 06:57:43

标签: python numpy

我刚刚开始使用NumPy,所以我可能会错过一些核心概念......

从值为列表的字典创建NumPy数组的最佳方法是什么?

这样的事情:

d = { 1: [10,20,30] , 2: [50,60], 3: [100,200,300,400,500] }

应该变成:

data = [
  [10,20,30,?,?],
  [50,60,?,?,?],
  [100,200,300,400,500]
]

我将对每一行做一些基本的统计,例如:

deviations = numpy.std(data, axis=1)

问题:

  • 从字典中创建numpy.array的最佳/最有效方法是什么?字典很大;几百万把钥匙,每件钥匙约有20件。

  • 每个'行'的值数不同。如果我理解正确numpy想要统一的大小,那么我为缺少的项目填写什么让std()开心?

更新:有一件事我忘了提及 - 虽然python技术是合理的(例如,循环几百万个项目很快),但它仅限于一个CPU。 Numpy操作可以很好地扩展到硬件并击中所有CPU,因此它们很有吸引力。

3 个答案:

答案 0 :(得分:8)

您不需要创建numpy数组来调用numpy.std()。 您可以在循环中调用numpy.std()覆盖字典的所有值。该列表将动态转换为numpy数组以计算标准变化。

这个方法的缺点是主循环将在python中,而不是在C中。但我想这应该足够快:你仍然会以C速度计算std,并且你将节省大量内存您不必在具有可变大小数组的位置存储0值。

  • 如果您想进一步优化它,可以将值存储到numpy数组列表中,这样就可以执行python列表 - > numpy数组转换只有一次。
  • 如果你发现这仍然太慢,请尝试使用psycho来优化python循环。
  • 如果这仍然太慢,请尝试将Cython与numpy模块一起使用。这个Tutorial声称图像处理的速度提升了很多。或者简单地在Cython中编写整个std函数(参见this了解基准和sum函数的例子)
  • Cython的替代方案是将SWIGnumpy.i一起使用。
  • 如果你只想使用numpy并且在C级别计算所有内容,请尝试将相同大小的所有记录组合在不同的数组中,并在每个数组上调用numpy.std()。它应该类似于以下示例。

O(N)复杂性的例子:

import numpy
list_size_1 = []
list_size_2 = []
for row in data.itervalues():
    if len(row) == 1:
      list_size_1.append(row)
    elif len(row) == 2:
      list_size_2.append(row)
list_size_1 = numpy.array(list_size_1)
list_size_2 = numpy.array(list_size_2)
std_1 = numpy.std(list_size_1, axis = 1)
std_2 = numpy.std(list_size_2, axis = 1)

答案 1 :(得分:2)

虽然这里已经有一些非常合理的想法,但我相信以下值得一提。

使用任何默认值填充缺失数据会破坏统计特征(标准等)。显然,这就是为什么Mapad提出了分组相同大小的记录的好方法。 它的问题(假设没有关于记录长度的任何先验数据就在眼前)是它涉及比直接解决方案更多的计算:

  1. 至少 O(N * logN)'len'调用以及使用有效算法进行排序的比较
  2. O(N)检查列表中的第二条路以获取组(它们在'垂直'轴上的起始和结束索引)
  3. 使用Psyco是一个好主意(它非常容易使用,所以一定要试一试)。

    似乎最佳方法是采用Mapad在#1中描述的策略,但需要修改 - 不要生成整个列表,而是遍历字典将每行转换为numpy.array并执行所需的计算。像这样:

    for row in data.itervalues():
        np_row = numpy.array(row)    
        this_row_std = numpy.std(np_row)
        # compute any other statistic descriptors needed and then save to some list
    

    无论如何,python中的几百万个循环不会像人们期望的那样长。除此之外,它看起来不像常规计算,所以如果它偶尔运行一次甚至只运行一次,谁会关心它是否需要额外的秒/分钟。


    Mapad建议的广义变体:

    from numpy import array, mean, std
    
    def get_statistical_descriptors(a):
        if ax = len(shape(a))-1
        functions = [mean, std]
        return f(a, axis = ax) for f in functions
    
    
    def process_long_list_stats(data):
        import numpy
    
        groups = {}
    
        for key, row in data.iteritems():
            size = len(row)
            try:
                groups[size].append(key)
            except KeyError:
                groups[size] = ([key])
    
        results = []
    
        for gr_keys in groups.itervalues():             
            gr_rows = numpy.array([data[k] for k in gr_keys])       
            stats = get_statistical_descriptors(gr_rows)                
            results.extend( zip(gr_keys, zip(*stats)) )
    
        return dict(results)
    

答案 2 :(得分:0)

numpy字典

您可以使用结构化数组来保留通过键(如字典)来处理numpy对象的能力。

import numpy as np


dd = {'a':1,'b':2,'c':3}
dtype = eval('[' + ','.join(["('%s', float)" % key for key in dd.keys()]) + ']')
values = [tuple(dd.values())]
numpy_dict = np.array(values, dtype=dtype)

numpy_dict['c']

现在输出

array([ 3.])