Python Numpy同时使用fromiter创建两个阵列
我有一个迭代器,看起来像下面这样Python Numpy同时使用fromiter创建两个阵列,python,arrays,numpy,Python,Arrays,Numpy,我有一个迭代器,看起来像下面这样 it = ((x, x**2) for x in range(20)) 我想要的是两个数组。一个是xs,另一个是x**2s,但我实际上不知道元素的数量,并且我无法从一个条目转换到另一个条目,因此我无法构建第一个条目,然后从第一个条目构建第二个条目 如果我只有一个未知大小的结果,我可以使用np.fromiter让它动态有效地分配,例如 y = np.fromiter((x[0] for x in it), float) 有了两个,我希望我能像 ita, itb
it = ((x, x**2) for x in range(20))
我想要的是两个数组。一个是x
s,另一个是x**2
s,但我实际上不知道元素的数量,并且我无法从一个条目转换到另一个条目,因此我无法构建第一个条目,然后从第一个条目构建第二个条目
如果我只有一个未知大小的结果,我可以使用np.fromiter
让它动态有效地分配,例如
y = np.fromiter((x[0] for x in it), float)
有了两个,我希望我能像
ita, itb = itertools.tee(it)
y = np.fromiter((x[0] for x in ita), float)
y2 = np.fromiter((x[1] for x in itb), float)
但是因为第一个调用耗尽了迭代器,我最好还是这样做
lst = list(it)
y = np.fromiter((x[0] for x in lst), float, len(lst))
y2 = np.fromiter((x[1] for x in lst), float, len(lst))
因为不管怎么说,tee都会填写一份与整个列表大小相同的表格。在将迭代器再次复制到数组之前,我希望避免将迭代器复制到列表中,但我想不出一种不完全手动地增量构建数组的方法。此外,
fromiter
似乎是用c编写的,因此用python编写它可能与首先制作一个列表没有不可忽略的区别。您可以使用np.fromiter
构建一个包含所有值的数组,然后对数组进行切片:
In [103]: it = ((x, x**2) for x in range(20))
In [104]: import itertools
In [105]: y = np.fromiter(itertools.chain.from_iterable(it), dtype=float)
In [106]: y
Out[106]:
array([ 0., 0., 1., 1., 2., 4., 3., 9., 4.,
16., 5., 25., 6., 36., 7., 49., 8., 64.,
9., 81., 10., 100., 11., 121., 12., 144., 13.,
169., 14., 196., 15., 225., 16., 256., 17., 289.,
18., 324., 19., 361.])
In [107]: y, y2 = y[::2], y[1::2]
In [108]: y
Out[108]:
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,
11., 12., 13., 14., 15., 16., 17., 18., 19.])
In [109]: y2
Out[109]:
array([ 0., 1., 4., 9., 16., 25., 36., 49., 64.,
81., 100., 121., 144., 169., 196., 225., 256., 289.,
324., 361.])
上面的代码将数据从迭代器加载到数组中,而不使用中间Python列表。但是,数组中的基础数据不是连续的。在连续阵列上,许多操作速度更快:
In [19]: a = np.arange(10**6)
In [20]: y1 = a[::2]
In [21]: z1 = np.ascontiguousarray(y1)
In [24]: %timeit y1.sum()
1000 loops, best of 3: 975 µs per loop
In [25]: %timeit z1.sum()
1000 loops, best of 3: 464 µs per loop
因此,您可能希望使y
和y2
连续:
y = np.ascontiguousarray(y)
y2 = np.ascontiguousarray(y2)
调用np.ascontiguousarray
需要在y
和y2
到新阵列中。不幸的是,我没有看到创建y
和
y2
作为连续数组,无需复制
下面是一个基准测试,比较了中间Python列表与NumPy切片的使用情况(使用和不使用
ascontiguousarray
):
与
np.array([(x,x**2)表示范围内的x(20)])
相比,这种链
方法快1.2倍(1.5倍表示范围更大)。是的,我考虑过这一点。这可能并不太糟糕,因为您正在将视图返回到更大的数组中。然而,我担心的是,由于条目在ram中的间隔会更大,所以我在读取数据后要执行的矩阵操作的效率会更低。这可能是我应该测试的。是的,在非连续数组上矩阵运算会慢一些。不幸的是,我看不到一种在不复制的情况下创建连续数组的方法。但是,上面确实避免了使用中间Python列表。
import numpy as np
import itertools as IT
def using_intermediate_list(g):
lst = list(g)
y = np.fromiter((x[0] for x in lst), float, len(lst))
y2 = np.fromiter((x[1] for x in lst), float, len(lst))
return y, y2
def using_slices(g):
y = np.fromiter(IT.chain.from_iterable(g), dtype=float)
y, y2 = y[::2], y[1::2]
return y, y2
def using_slices_contiguous(g):
y = np.fromiter(IT.chain.from_iterable(g), dtype=float)
y, y2 = y[::2], y[1::2]
y = np.ascontiguousarray(y)
y2 = np.ascontiguousarray(y2)
return y, y2
def using_array(g):
y = np.array(list(g))
y, y2 = y[:, 0], y[:, 1]
return y, y2
In [27]: %timeit using_intermediate_list(((x, x**2) for x in range(10**6)))
1 loops, best of 3: 376 ms per loop
In [28]: %timeit using_slices(((x, x**2) for x in range(10**6)))
1 loops, best of 3: 220 ms per loop
In [29]: %timeit using_slices_contiguous(((x, x**2) for x in range(10**6)))
1 loops, best of 3: 237 ms per loop
In [34]: %timeit using_array(((x, x**2) for x in range(10**6)))
1 loops, best of 3: 707 ms per loop