迭代一个带有两个隐式循环的数组

时间:2013-10-01 13:19:14

标签: python loops numpy indexing

是否可以在具有两个索引的数组上隐式迭代? 这是我想要做的一个非常简单的例子:

import numpy as np

x = np.arange(3)
y = np.zeros(3)

for i in range(3):
    y[i] = np.sum(x - x[i])

有一个隐式循环(总和)和一个显式循环(for i in range(3))......是否有可能拥有完全隐式的版本?

2 个答案:

答案 0 :(得分:4)

如果可能的话,你应该在计算机科学之前尝试使用数学。您的表达式y[i] = np.sum(x - x[i])可以用y[i] = np.sum(x) - x.size * x[i]的小代数重写。这清楚地表明您可以在没有任何循环的情况下重写代码:

y = np.sum(x) - x.size * x

显而易见,对于大型阵列,它运行速度比@JoshAdel的解决方案快得多,对于大小为1000的输入,x400更快:

>>> x = np.random.normal(size=(1000,))
>>> np.allclose(np.sum(x - x[:,None], 1), np.sum(x) - x.size * x)
True

%timeit np.sum(x - x[:,None], 1)
100 loops, best of 3: 6.33 ms per loop

%timeit np.sum(x) - x.size * x
100000 loops, best of 3: 16.5 us per loop

答案 1 :(得分:3)

以下内容应该有效:

y = np.sum(x - x[:,None], axis=1)

此解决方案正在使用numpy的广播设施。首先,我使用x重新构建(N,)形状(N,1)x[:,None]的{​​{1}}。您可能还会将其视为x[:,np.newaxis]

x - x[:,None]创建一个(N,N)数组,其元素为tmp_{i,j} = x_i - x_j。然后,我使用axis=1中的参数np.sum对行进行求和。

请参阅:

In [13]: y = np.zeros(10)

In [14]: x = np.random.normal(size=(10,))

In [15]: for i in range(10):
        y[i] = np.sum(x - x[i])
   ....:

In [16]: y
Out[16]:
array([  7.99781458,   4.15114434, -17.24655912, -20.35606168,
        -5.0211756 ,   7.52062868,   8.2501526 ,   3.90397351,
        10.18746451,   0.61261819])

In [17]: np.sum(x - x[:,None], 1)
Out[17]:
array([  7.99781458,   4.15114434, -17.24655912, -20.35606168,
        -5.0211756 ,   7.52062868,   8.2501526 ,   3.90397351,
        10.18746451,   0.61261819])

In [18]: np.allclose(y, np.sum(x - x[:,None], 1))
Out[18]: True

时间:只是要指出使用numpy为数组操作提供的功能通常比使用标准Python结构快得多:

In [48]: x = np.random.normal(size=(100,))

In [49]: %timeit y = np.array([sum(x - k) for k in x])
100 loops, best of 3: 6.86 ms per loop

In [67]: %timeit y = np.array([np.sum(x - k) for k in x])
1000 loops, best of 3: 1.54 ms per loop

In [50]: %timeit np.sum(x - x[:,None], 1)
10000 loops, best of 3: 59 µs per loop

In [51]:

In [51]: x = np.random.normal(size=(1000,))

In [52]: %timeit y = np.array([sum(x - k) for k in x])
1 loops, best of 3: 592 ms per loop

In [72]: %timeit y = np.array([np.sum(x - k) for k in x])
100 loops, best of 3: 17.2 ms per loop

In [53]: %timeit np.sum(x - x[:,None], 1)
100 loops, best of 3: 8.67 ms per loop