Python 中数组元素的迭代减法
Iterative subtraction of elements in array in Python
我有一个很大的 numpy 数组。有没有一种方法可以在不使用循环的情况下将每个元素与其下方的元素相减,并将结果存储在新的 list/array 中。
我的意思的一个简单例子:
a = numpy.array([4,3,2,1])
result = [4-3, 4-2, 4-1, 3-2, 3-1, 2-1] = [1, 2, 3, 1, 2 ,1]
请注意,我正在使用的 'real' 数组不包含按顺序排列的数字。这只是为了简化示例。
我知道结果应该有(n-1)!元素,其中 n 是数组的大小。
有没有办法不使用循环,而是以 'smart' 的方式重复数组来做到这一点?
谢谢!
a = [4, 3, 2, 1]
differences = ((x - y) for i, x in enumerate(a) for y in a[i+1:])
for diff in differences:
# do something with difference.
pass
from itertools import combinations
l = [4, 3, 2, 1]
result = []
for n1, n2 in combinations(l, 2):
result.append(n1 - n2)
print result
结果:
[1, 2, 3, 1, 2, 1]
combinations
returns 一个生成器,所以这对非常大的列表很有用:)
temp = a[:, None] - a
result = temp[np.triu_indices(len(a), k=1)]
执行所有成对减法以产生temp
,包括从自身中减去元素和从后面的元素中减去前面的元素,然后使用triu_indices
到select我们想要的结果。 (a[:, None]
adds an extra length-1 axis to a
.)
请注意,几乎所有的运行时间都花在从 temp
构造 result
上(因为 triu_indices
很慢并且使用索引到 select 数组的上三角是慢的)。如果可以直接使用temp
,可以节省很多时间:
In [13]: a = numpy.arange(2000)
In [14]: %%timeit
....: temp = a[:, None] - a
....:
100 loops, best of 3: 6.99 ms per loop
In [15]: %%timeit
....: temp = a[:, None] - a
....: result = temp[numpy.triu_indices(len(a), k=1)]
....:
10 loops, best of 3: 51.7 ms per loop
这是一种基于 masking
的方法,用于广播减法后的提取和掩码创建,我们再次使用 broadcasting
(可以说是双 broadcasting
供电)-
r = np.arange(a.size)
out = (a[:, None] - a)[r[:,None] < r]
运行时测试
矢量化方法 -
# @user2357112's solution
def pairwise_diff_triu_indices_based(a):
return (a[:, None] - a)[np.triu_indices(len(a), k=1)]
# Proposed in this post
def pairwise_diff_masking_based(a):
r = np.arange(a.size)
return (a[:, None] - a)[r[:,None] < r]
计时 -
In [109]: a = np.arange(2000)
In [110]: %timeit pairwise_diff_triu_indices_based(a)
10 loops, best of 3: 36.1 ms per loop
In [111]: %timeit pairwise_diff_masking_based(a)
100 loops, best of 3: 11.8 ms per loop
仔细查看涉及的性能参数
让我们深入了解一下此设置的时序,以研究基于遮罩的方法有多大帮助。现在,为了进行比较,有两个部分 - Mask 创建与索引创建以及基于 Mask 的布尔索引与基于整数的索引。
创建蒙版有多大帮助?
In [37]: r = np.arange(a.size)
In [38]: %timeit np.arange(a.size)
1000000 loops, best of 3: 1.88 µs per loop
In [39]: %timeit r[:,None] < r
100 loops, best of 3: 3 ms per loop
In [40]: %timeit np.triu_indices(len(a), k=1)
100 loops, best of 3: 14.7 ms per loop
关于 5x
对掩码创建相对于索引设置的改进。
布尔索引对基于整数的索引有多大帮助?
In [41]: mask = r[:,None] < r
In [42]: idx = np.triu_indices(len(a), k=1)
In [43]: subs = a[:, None] - a
In [44]: %timeit subs[mask]
100 loops, best of 3: 4.15 ms per loop
In [45]: %timeit subs[idx]
100 loops, best of 3: 10.9 ms per loop
关于 2.5x
改进。
我有一个很大的 numpy 数组。有没有一种方法可以在不使用循环的情况下将每个元素与其下方的元素相减,并将结果存储在新的 list/array 中。
我的意思的一个简单例子:
a = numpy.array([4,3,2,1])
result = [4-3, 4-2, 4-1, 3-2, 3-1, 2-1] = [1, 2, 3, 1, 2 ,1]
请注意,我正在使用的 'real' 数组不包含按顺序排列的数字。这只是为了简化示例。
我知道结果应该有(n-1)!元素,其中 n 是数组的大小。
有没有办法不使用循环,而是以 'smart' 的方式重复数组来做到这一点?
谢谢!
a = [4, 3, 2, 1]
differences = ((x - y) for i, x in enumerate(a) for y in a[i+1:])
for diff in differences:
# do something with difference.
pass
from itertools import combinations
l = [4, 3, 2, 1]
result = []
for n1, n2 in combinations(l, 2):
result.append(n1 - n2)
print result
结果:
[1, 2, 3, 1, 2, 1]
combinations
returns 一个生成器,所以这对非常大的列表很有用:)
temp = a[:, None] - a
result = temp[np.triu_indices(len(a), k=1)]
执行所有成对减法以产生temp
,包括从自身中减去元素和从后面的元素中减去前面的元素,然后使用triu_indices
到select我们想要的结果。 (a[:, None]
adds an extra length-1 axis to a
.)
请注意,几乎所有的运行时间都花在从 temp
构造 result
上(因为 triu_indices
很慢并且使用索引到 select 数组的上三角是慢的)。如果可以直接使用temp
,可以节省很多时间:
In [13]: a = numpy.arange(2000)
In [14]: %%timeit
....: temp = a[:, None] - a
....:
100 loops, best of 3: 6.99 ms per loop
In [15]: %%timeit
....: temp = a[:, None] - a
....: result = temp[numpy.triu_indices(len(a), k=1)]
....:
10 loops, best of 3: 51.7 ms per loop
这是一种基于 masking
的方法,用于广播减法后的提取和掩码创建,我们再次使用 broadcasting
(可以说是双 broadcasting
供电)-
r = np.arange(a.size)
out = (a[:, None] - a)[r[:,None] < r]
运行时测试
矢量化方法 -
# @user2357112's solution
def pairwise_diff_triu_indices_based(a):
return (a[:, None] - a)[np.triu_indices(len(a), k=1)]
# Proposed in this post
def pairwise_diff_masking_based(a):
r = np.arange(a.size)
return (a[:, None] - a)[r[:,None] < r]
计时 -
In [109]: a = np.arange(2000)
In [110]: %timeit pairwise_diff_triu_indices_based(a)
10 loops, best of 3: 36.1 ms per loop
In [111]: %timeit pairwise_diff_masking_based(a)
100 loops, best of 3: 11.8 ms per loop
仔细查看涉及的性能参数
让我们深入了解一下此设置的时序,以研究基于遮罩的方法有多大帮助。现在,为了进行比较,有两个部分 - Mask 创建与索引创建以及基于 Mask 的布尔索引与基于整数的索引。
创建蒙版有多大帮助?
In [37]: r = np.arange(a.size)
In [38]: %timeit np.arange(a.size)
1000000 loops, best of 3: 1.88 µs per loop
In [39]: %timeit r[:,None] < r
100 loops, best of 3: 3 ms per loop
In [40]: %timeit np.triu_indices(len(a), k=1)
100 loops, best of 3: 14.7 ms per loop
关于 5x
对掩码创建相对于索引设置的改进。
布尔索引对基于整数的索引有多大帮助?
In [41]: mask = r[:,None] < r
In [42]: idx = np.triu_indices(len(a), k=1)
In [43]: subs = a[:, None] - a
In [44]: %timeit subs[mask]
100 loops, best of 3: 4.15 ms per loop
In [45]: %timeit subs[idx]
100 loops, best of 3: 10.9 ms per loop
关于 2.5x
改进。