【问题标题】:convert itertools array into numpy array将 itertools 数组转换为 numpy 数组
【发布时间】:2016-01-21 19:28:10
【问题描述】:

我正在创建这个数组:

A=itertools.combinations(range(6),2)

我必须用 numpy 操作这个数组,比如:

A.reshape(..

如果维度是A高,则list(A)的命令太慢了。

如何将 itertools 数组“转换”为 numpy 数组?

更新 1: 我已经尝试过hpaulj的解决方案,在这种特定情况下会慢一点,有什么想法吗?

start=time.clock()

A=it.combinations(range(495),3)
A=np.array(list(A))
print A

stop=time.clock()
print stop-start
start=time.clock()

A=np.fromiter(it.chain(*it.combinations(range(495),3)),dtype=int).reshape (-1,3)
print A

stop=time.clock()
print stop-start

结果:

[[  0   1   2]
 [  0   1   3]
 [  0   1   4]
 ..., 
 [491 492 494]
 [491 493 494]
 [492 493 494]]
10.323822
[[  0   1   2]
 [  0   1   3]
 [  0   1   4]
 ..., 
 [491 492 494]
 [491 493 494]
 [492 493 494]]
12.289898

【问题讨论】:

  • 您好,请问您的问题在哪里?
  • 如何将 itertools 数组“转换”为 numpy 数组?
  • 你确定不是“太慢”,因为组合的数量太大了吗?如果您尝试创建十亿个元素或其他东西,那总是需要一段时间。 itertools.combinations 调用立即返回,因为它实际上并没有预先创建任何组合,它是一个生成器。

标签: python numpy itertools


【解决方案1】:

我重新打开它是因为我不喜欢链接的答案。接受的答案建议使用

np.array(list(A))  # producing a (15,2) array

但是 OP 显然已经尝试过list(A),发现它很慢。

另一个答案建议使用np.fromiter。但隐藏在其 cmets 中的是 fromiter 需要一维数组的注释。

In [102]: A=itertools.combinations(range(6),2)
In [103]: np.fromiter(A,dtype=int)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-103-29db40e69c08> in <module>()
----> 1 np.fromiter(A,dtype=int)

ValueError: setting an array element with a sequence.

因此,将 fromiter 与此 itertools 一起使用需要以某种方式展平迭代器。

一组快速的时间表明list 并不是缓慢的一步。它将列表转换为一个很慢的数组:

In [104]: timeit itertools.combinations(range(6),2)
1000000 loops, best of 3: 1.1 µs per loop
In [105]: timeit list(itertools.combinations(range(6),2))
100000 loops, best of 3: 3.1 µs per loop
In [106]: timeit np.array(list(itertools.combinations(range(6),2)))
100000 loops, best of 3: 14.7 µs per loop

我认为使用fromiter 的最快方法是使用itertools.chain 的惯用用法来扁平化combinations

In [112]: timeit
np.fromiter(itertools.chain(*itertools.combinations(range(6),2)),dtype=int)
   .reshape(-1,2)
100000 loops, best of 3: 12.1 µs per loop

并没有节省多少时间,至少在这么小的尺寸上是这样。 (fromiter 也需要 count,这会减少另一个 µs。对于更大的情况,range(60)fromiter 需要 array 的一半时间。


[numpy] itertools 上快速搜索会发现一些关于生成所有组合的纯 numpy 方法的建议。 itertools 速度很快,用于生成纯 Python 结构,但将它们转换为数组是一个缓慢的步骤。


对问题的挑剔。

A 是一个生成器,而不是一个数组。 list(A) 确实产生了一个嵌套列表,可以松散地描述为一个数组。但它不是np.array,也没有reshape 方法。

【讨论】:

  • 您可以通过指定最终数组的大小来从np.fromiter 中榨取更多性能,可以使用scipy.special.binom(6, 2) 进行计算
  • @hpaulj 我已经尝试过您的解决方案,请查看问题中的更新
  • 有纯粹的 numpy 方法可以生成更快的组合。 @all_m 建议使用triu。我相信在之前的 SO 问题中已经提出了其他建议。
  • A quick search on [numpy] itertools turns up a number of suggestions of pure numpy ways of generating all combinations. @hpaulj 你介意链接其中一些吗,因为我找不到任何东西?
【解决方案2】:

获取N 元素的每个成对组合的另一种方法是使用np.triu_indices(N, k=1) 生成(N, N) 矩阵的上三角形的索引,例如:

np.vstack(np.triu_indices(6, k=1)).T

对于小型数组,itertools.combinations 会胜出,但对于大型 Ntriu_indices 技巧可以更快:

In [1]: %timeit np.fromiter(itertools.chain.from_iterable(itertools.combinations(range(6), 2)), np.int)
The slowest run took 10.46 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 4.04 µs per loop

In [2]: %timeit np.array(np.triu_indices(6, 1)).T
The slowest run took 10.97 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 22.3 µs per loop

In [3]: %timeit np.fromiter(itertools.chain.from_iterable(itertools.combinations(range(1000), 2)), np.int)
10 loops, best of 3: 69.7 ms per loop

In [4]: %timeit np.array(np.triu_indices(1000, 1)).T
100 loops, best of 3: 10.6 ms per loop

【讨论】:

  • 我认为该解决方案不会产生超过两个元素的组合
  • 是的,我提到它是因为您最初的问题是关于两个元素的组合。我认为可以推广这种方法来处理两个以上元素的组合,但需要更多的思考。
  • 我不知道chain.fromiterable。对于大型案例,它的速度是 chain(*...) 的两倍。
猜你喜欢
  • 1970-01-01
  • 2021-12-29
  • 2017-03-08
  • 2021-03-10
  • 2011-11-27
  • 1970-01-01
  • 2021-12-18
  • 2012-04-18
  • 2019-08-30
相关资源
最近更新 更多