【问题标题】:python dict to numpy structured arraypython dict到numpy结构化数组
【发布时间】:2013-03-12 20:36:58
【问题描述】:

我有一本字典,需要将其转换为 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)

【问题讨论】:

    标签: python numpy arcpy


    【解决方案1】:

    我更喜欢将键和值存储在单独的数组中。这个我经常比较实用。数组结构是结构数组的完美替代品。在大多数情况下,您只需处理数据的子集(在这种情况下为键或值,仅对两个数组中的一个进行操作会比同时对两个数组中的一半进行操作更有效。

    但如果这种方式不可行,我建议使用按列而不是按行排序的数组。这样,您将获得与拥有两个数组相同的好处,但只打包在一个中。

    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)}
    

    【讨论】:

    • 请在发布之前测试您的代码。在您的第一个代码示例中,未指定 r,在您的第二个代码示例中未指定 k
    • 如果这些值是一个复杂类型,比如浮点数数组。我们将如何在您的代码中定义这种类型?
    【解决方案2】:

    类似于批准的答案。如果你想从字典键创建一个数组:

    np.array( tuple(dict.keys()) )
    

    如果你想从字典值创建一个数组:

    np.array( tuple(dict.values()) )
    

    【讨论】:

      【解决方案3】:

      你可以使用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 explains:

      通常,元组被认为是“标量”记录,而列表是 递归。此规则有助于 numpy.array() 找出哪个 序列是记录,哪些是要递归的其他序列 之上;即哪些序列创建另一个维度,哪些是 原子元素。

      由于(0.0, 1.1181753789488595) 被认为是这些原子元素之一,它应该是一个元组,而不是一个列表。

      【讨论】:

      • 我参考了你的这个答案来让事情发生,但它不起作用。在这上面花了几天时间。你能帮忙吗? stackoverflow.com/questions/32723802/…
      • 直接复制和粘贴代码示例会出错。我通过将result.items() 更改为list(result.items()) 来修复它。 Python 3.5
      • @Atlas7:感谢您的提醒。已针对 Python3 更新了答案。
      【解决方案4】:

      如果您接受使用 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
      

      【讨论】:

      • 我承认这就是我所做的,一般来说,DataFrames 在处理大量数据时比 np 数组更有效。你应该添加:df = df.to_numpy().T.
      【解决方案5】:

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

      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
      

      【讨论】:

        猜你喜欢
        • 2018-08-09
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 2018-12-19
        • 1970-01-01
        • 2016-03-29
        • 2012-08-12
        • 2016-04-28
        相关资源
        最近更新 更多