【问题标题】:Build Dictionary and List from Numpy Ndarray从 Numpy Ndarray 构建字典和列表
【发布时间】:2020-01-02 06:31:47
【问题描述】:

我想为数百万个数据创建一个使用 2D ndarray 的字典。

寻找一种pythonic和高性能的方式来实现这一目标

我的 ndarray:

格式:[id, origin_lat, origin_lon, dest_lat,dest_lon, 距离]

my_array = np.array([[245, 32.45,63.89,72.1,63.57,123.45],
[246, 61.73,42.71,75.54,-81.69,16.32]])

预期输出:

my_dict = {
        245: {
            'origin_lat_lon': {
                'lat': 32.45,
                'lon': 63.89
            },
            'dest_lat_lon': {
                'lat': 72.1,
                'lon': 63.57
            },
            'distance': 123.45
        },
        246: {
            'origin_lat_lon': {
                'lat': 61.73,
                'lon': 42.71
            },
            'dest_lat_lon': {
                'lat': 75.54,
                'lon': -81.69
            },
            'distance': 16.32
        }
    }

my_list = [{'lat': 32.45, 'lon': 63.89},
 {'lat': 72.1, 'lon': 63.57},
 {'lat': 61.73, 'lon': 42.71},
 {'lat': 75.54, 'lon': -81.69}]

我的代码:

my_dict = dict()
my_list = list()

for arr in my_array:
    origin_lat_lon = {'lat': arr[1],
                            'lon': arr[2]}
    dest_lat_lon  = {'lat': arr[3],
                  'lon': arr[4]}
    value = {'origin_lat_lon':origin_lat_lon,'dest_lat_lon':dest_lat_lon,'distance':arr[5]}
    my_dict[int(arr[0])]=value
    my_list.append(origin_lat_lon)
    my_list.append(dest_lat_lon)

【问题讨论】:

  • @Chris 你说得对,刚刚更新了预期的输出

标签: python numpy dictionary


【解决方案1】:

这是将dictzipslicing 结合使用的一种方法。

例如:

import numpy as np

my_array = np.array([[245, 32.45,63.89,72.1,63.57,123.45],[246, 61.73,42.71,75.54,-81.69,16.32]])
keys = ['origin_lat', 'origin_lon', 'dest_lat','dest_lon', 'distance']
keys_2 = ['lat', 'lon']

my_dict = {}
my_list = []

for arr in my_array:
    key, vals = arr[0], arr[1:]
    my_dict[int(key)] = dict(zip(keys, vals))
    my_list.extend([[dict(zip(keys_2, vals[0:2]))],[dict(zip(keys_2, vals[2:4]))]])

print(my_dict)
print(my_list)

输出:

{245: {'dest_lat': 72.1,
       'dest_lon': 63.57,
       'distance': 123.45,
       'origin_lat': 32.45,
       'origin_lon': 63.89},
 246: {'dest_lat': 75.54,
       'dest_lon': -81.69,
       'distance': 16.32,
       'origin_lat': 61.73,
       'origin_lon': 42.71}}
[[{'lat': 32.45, 'lon': 63.89}],
 [{'lat': 72.1, 'lon': 63.57}],
 [{'lat': 61.73, 'lon': 42.71}],
 [{'lat': 75.54, 'lon': -81.69}]]

【讨论】:

  • 常规 python for 循环对于数百万个数据来说很慢。我正在寻找类似 numpy.vectorize 或任何你明确不循环数组的东西
  • numpy vectorize 表示使用已编译的 numpy 方法,这些方法主要是计算性的。您正在创建 Python 对象 - 列表和字典,最终是 json 字符串。没有为此编译的 numpy 代码。
  • @min2bro 注意,numpy.vectorize 只是一个 Python for 循环,它是为了方便而不是性能。
【解决方案2】:

您的代码包装在一个函数中,次:

In [220]: timeit foo(my_array)                                                  
7.14 µs ± 17.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

将数组转换为列表可将时间缩短一半。 tolist() 是一种(相对)快速的将数组转换为嵌套列表的方法。迭代列表比迭代数组更快:

In [221]: timeit foo(my_array.tolist())                                         
2.68 µs ± 14.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Rakesh 的版本有点慢(我还没有确定原因):

In [222]: timeit rakesh(my_array)                                               
18.5 µs ± 63.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [223]: timeit rakesh(my_array.tolist())                                      
9.49 µs ± 26.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Chris 的 pandas 版本要慢一些。 pandas 确实有一个很好的字典接口,但显然它并不快。它可能是纯 Python,并且由于通用而降低了速度。

In [224]: timeit foo_pd(my_array)                                               
3.35 ms ± 5.69 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Python 字典的工作效率很高,但仍必须逐个键地访问它们。 numpy 没有自己的编译代码来处理字典。

===

您的数组可以转换为结构化数组。用这些列替换字段,按名称访问。所以它更像字典,虽然对于创建json 输出可能没有更好的效果。 (而且它不是速度工具)

In [225]: dt = np.dtype([('id',int),('origin_lat',float),('origin_lon',float),('
     ...: dest_lat',float),('dest_lon',float),('distance',float)])              
In [226]: import numpy.lib.recfunctions as rf                                   

In [228]: sarr =rf.unstructured_to_structured(my_array, dt)                     
In [229]: sarr                                                                  
Out[229]: 
array([(245, 32.45, 63.89, 72.1 ,  63.57, 123.45),
       (246, 61.73, 42.71, 75.54, -81.69,  16.32)],
      dtype=[('id', '<i8'), ('origin_lat', '<f8'), ('origin_lon', '<f8'), ('dest_lat', '<f8'), ('dest_lon', '<f8'), ('distance', '<f8')])

In [230]: sarr['dest_lon']                                                      
Out[230]: array([ 63.57, -81.69])

In [236]: timeit sarr =rf.unstructured_to_structured(my_array, dt)              
46.3 µs ± 1.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

  • 熊猫版本使用.apply,这基本上只是一个常规的旧循环。除了这种方法具有创建数据框等的所有额外开销
  • 这些解决方案都没有真正加速整个计算。甚至我在 timeit 方面的解决方案也接近这两种解决方案。我的问题是优化代码以在百万数据点上运行它。
  • 我的观点是,由于您正在创建 Python 字典,因此没有办法显着加快速度,至少不是通常的 numpy 意义上的。我不知道编译器工具之一,numbacython 是否可以提供帮助。
猜你喜欢
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 2015-06-30
  • 2016-02-10
  • 2015-09-16
  • 2015-09-30
  • 2018-07-28
  • 1970-01-01
相关资源
最近更新 更多