目标
给定一个二维数组 A
,我必须不断将每列第一行的值加 +1,直到各列的总和等于相同的值,例如 28 .
我的解决方案
这可能不是最好的解决方案,但考虑到我想表达的观点,它就可以了。这是一个简化的示例。在原始版本中,它基于第一行或第二行是否获得+1的概率分布,并且在列之间有所不同。另外,它必须逐一完成,因为概率分布会因上一周期中某一列的第一行或第二行是否获得+1而发生变化。所以列的求和和迭代是必要的。
import numpy as np
A = np.arange(20).reshape(2, 10)
print(A)
MASK = A.sum(axis=0) < 28
print(A.sum(axis=0) < 28)
while np.any(MASK):
LUCKYROW = np.repeat(0, np.count_nonzero(MASK))
A[LUCKYROW, MASK] += 1
MASK = A.sum(axis=0) < 28
print(A.sum(axis=0) < 28)
print(A)
让我们看一下输出:
[[ 0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]]
[ True True True True True True True True True False]
[ True True True True True True True True True False]
[ True True True True True True True True False False]
[ True True True True True True True True False False]
[ True True True True True True True False False False]
[ True True True True True True True False False False]
[ True True True True True True False False False False]
[ True True True True True True False False False False]
[ True True True True True False False False False False]
[ True True True True True False False False False False]
[ True True True True False False False False False False]
[ True True True True False False False False False False]
[ True True True False False False False False False False]
[ True True True False False False False False False False]
[ True True False False False False False False False False]
[ True True False False False False False False False False]
[ True False False False False False False False False False]
[ True False False False False False False False False False]
[False False False False False False False False False False]
[[18 17 16 15 14 13 12 11 10 9]
[10 11 12 13 14 15 16 17 18 19]]
好吧,确实可以,但是为什么每次循环都要计算每一列的总和呢?根据之前的周期,我知道哪一列的总和已经达到目标值。如果我利用这些信息,也许可以节省时间。
我的第二个解决方案
import numpy as np
A = np.arange(20).reshape(2, 10)
print(A)
MASK = A.sum(axis=0) < 28
print(A.sum(axis=0) < 28)
while np.any(MASK):
LUCKYROW = np.repeat(0, np.count_nonzero(MASK))
A[LUCKYROW, MASK] += 1
MASK[MASK] = A[:, MASK].sum(axis=0) < 28
print(A[:, MASK].sum(axis=0) < 28)
print(A)
输出:
[[ 0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]]
[ True True True True True True True True True False]
[ True True True True True True True True True]
[ True True True True True True True True]
[ True True True True True True True True]
[ True True True True True True True]
[ True True True True True True True]
[ True True True True True True]
[ True True True True True True]
[ True True True True True]
[ True True True True True]
[ True True True True]
[ True True True True]
[ True True True]
[ True True True]
[ True True]
[ True True]
[ True]
[ True]
[]
[[18 17 16 15 14 13 12 11 10 9]
[10 11 12 13 14 15 16 17 18 19]]
这似乎有效。虽然出现了一个问题。它不比第一个解决方案快。我尝试过使用 25000 列和 74998 作为目标值,但它们在时间上大致相等。
我的请求
我认为我可能对 ndarray 操作或 ndarray 索引有根本性的误解。第二个解决方案应该在每个周期进行越来越少的计算,因此我预计性能会显着提高。我无法找到解释。我的思路哪里出了问题?
最佳答案
由于您只更改第一行,因此无需在每次迭代时重新计算列的总和。事实上,由于唯一的变化是向第一行的某些元素添加 1,因此您根本不需要迭代。
A = np.arange(20).reshape(2, 10)
s = A.sum(0)
d = max(s) - s
A[0] += d
>>> A
array([[18, 17, 16, 15, 14, 13, 12, 11, 10, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
这对于更复杂的计算来说可能是不可能的,但对于求和来说这是一个简单的捷径。
可能有几个原因导致您的“更快”代码实际上运行得更快。
首先,对实际分析代码表示赞赏。
第一个原因是A
非常小。
一般来说,numpy
仅当数组中有数千或数万个元素时才会带来速度优势。
第二,在“更快”的代码行
MASK[MASK] = A[:, MASK].sum(axis=0) < 28
创建 A
中所有行的副本索引为 MASK
。
这可能是一个相当昂贵的操作,因此使用 MASK = A.sum(axis=0) < 28
对原始版本中的额外行求和。可能会更快,因为它不需要额外的副本。
关于python - 有没有办法不计算不必要的金额来节省时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56407739/