- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个已知大小为 N 的向量 a
,因此 np.sum(a)
为 1,并且 np.all(a>=0 )
是正确的。我想确定达到阈值 t 的最小条目数。例如,我会做类似的事情:
idx = np.argsort(a)
asorted = a[idx][::-1]
sum_ = 0
number = 0
while sum_ < t:
number += 1
sum_ = np.sum(asorted[:number])
一旦 sum_
大于 t
,程序就会停止,变量 number
告诉我求和的最小条目数该阈值。
我正在寻找获取此数字的最有效方法,因为我必须执行此操作数百万次。
最佳答案
(已编辑)
(EDIT2:添加了更专业的 JIT 版本,以解决将 np.sort()
与 numba
一起使用时出现的问题。)
(EDIT3:包括从 @hilberts_drinking_problem's answer 开始中值旋转的递归方法的计时)
我并不是100%你想要的,因为你的代码的前两行似乎什么也没做,但是在@hilberts_drinking_problem之后我编辑了我的答案,我假设你有一个错字并且:
sum_ = np.sum(arr[:i])
应该是:
sum_ = np.sum(asorted[:i])
<小时/>
然后,您的解决方案可以编写为如下函数:
import numpy as np
def min_sum_threshold_orig(arr, threshold=0.5):
idx = np.argsort(arr)
arr_sorted = arr[idx][::-1]
sum_ = 0
i = 0
while sum_ < threshold:
i += 1
sum_ = np.sum(arr_sorted[:i])
return i
但是:
np.sort()
而不是 np.argsort()
和索引threshold
足够高(您的假设为 > 1.0
),那么循环将永远不会结束解决这些问题可以:
def min_sum_threshold(arr, threshold=0.5):
arr = np.sort(arr)[::-1]
sum_ = 0
for i in range(arr.size):
sum_ += arr[i]
if sum_ >= threshold:
break
return i + 1
在上面,显式循环成为瓶颈。解决这个问题的一个好方法是使用 numba
:
import numba as nb
min_sum_threshold_nbn = nb.jit(min_sum_threshold)
min_sum_threshold_nbn.__name__ = 'min_sum_threshold_nbn'
但这可能不是最有效的方法,因为创建新数组时 numba
相对较慢。一种可能更快的方法是使用 arr.sort() 代替 np.sort() ,因为它是就地的,从而避免创建新数组:
@nb.jit
def min_sum_thres_nb_inplace(arr, threshold=0.5):
arr.sort()
sum_ = 0
for i in range(arr.size - 1, -1, -1):
sum_ += arr[i]
if sum_ >= threshold:
break
return arr.size - i
或者,可以仅 JIT 排序后的代码部分:
@nb.jit
def _min_sum_thres_nb(arr, threshold=0.5):
sum_ = 0.0
for i in range(arr.size):
sum_ += arr[i]
if sum_ >= threshold:
break
return i + 1
def min_sum_thres_nb(arr, threshold=0.5):
return _min_sum_thres_nb(np.sort(arr)[::-1], threshold)
对于较大的输入,两者之间的差异将很小。对于较小的情况,min_sum_thres_nb()
将由相对较慢的额外函数调用主导。由于修改其输入的基准测试函数存在缺陷,因此基准测试中省略了 min_sum_thres_nb_inplace()
,但要理解的是,对于非常小的输入,其速度与 min_sum_thres_nbn()
一样快,并且对于较大的,它的性能与 min_sum_thres_nb()
基本相同。
或者可以使用矢量化方法,如@yatu's answer :
def min_sum_threshold_np_sum(arr, threshold=0.5):
return np.sum(np.cumsum(np.sort(arr)[::-1]) < threshold) + 1
或者,更好的是,使用np.searchsorted()
,这样可以避免通过比较创建不必要的临时数组:
def min_sum_threshold_np_ss(arr, threshold=0.5):
return np.searchsorted(np.cumsum(np.sort(arr)[::-1]), threshold) + 1
或者,假设对整个数组进行排序的成本不必要地高:
def min_sum_threshold_np_part(arr, threshold=0.5):
n = arr.size
m = np.int(size * threshold) + 1
part_arr = np.partition(arr, n - m)[n - m:]
return np.searchsorted(np.cumsum(np.sort(arr)[::-1]), threshold) + 1
使用递归和中值旋转的更复杂的方法是:
def min_sum_thres_rec(arr, threshold=0.5, cutoff=64):
n = arr.size
if n <= cutoff:
return np.searchsorted(np.cumsum(np.sort(arr)[::-1]), threshold) + 1
else:
m = n // 2
partitioned = np.partition(arr, m)
low = partitioned[:m]
high = partitioned[m:]
sum_high = np.sum(high)
if sum_high >= threshold:
return min_sum_thres_rec(high, threshold)
else:
return min_sum_thres_rec(low, threshold - sum_high) + high.size
(后三个改编自@hilberts_drinking_problem's answer)
<小时/>使用由此生成的输入对这些进行基准测试:
def gen_input(n, a=0, b=10000):
arr = np.random.randint(a, b, n)
arr = arr / np.sum(arr)
return arr
给出以下内容:
这些表明,对于足够小的输入,numba
方法是最快的,但是一旦输入超过朴素方法的约 600 个元素或优化方法的约 900 个元素, em> 第一,使用 np.partition() 的 NumPy 方法虽然内存效率较低,但速度更快。
最终,超过约 4000 个元素,min_sum_thres_rec()
比所有其他建议的方法更快。也许可以为此方法编写一个更快的基于 numba 的实现。
请注意,优化 numba
方法比经过测试的简单 NumPy 方法要快。
关于python - Python中的高效累加和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60661015/
我对编程非常陌生(所以我提前道歉),并且我无法弄清楚如何创建一个 for 循环来执行以下操作: 我要求用户输入两个变量(我将它们称为 x 和 y),然后我计算 x/y = z。我想提出这个两个变量输入
我正在尝试对 vector 使用累加函数 vector A; double B = 0; A.reserve(100); for(itr = 0; itr < 210; itr++) { t
如果我想累积 std::vector 的绝对值,我可以使用 lambda 来计算绝对值并将其添加到 std::accumulate #include int main (){ std::ve
所以我需要使用 accumulate 对 vector 中的一些 double 值求和,其中我的 VECTOR 实际上是指向对象的指针。 现在,当我将 accumulate 与 int 一起用于 in
假设我有一个 (None, 2)-shape 张量 indices 和 (None,)-shape 张量 values。这些实际行号和值将在运行时确定。 我想设置一个 4x5 张量 t,索引的每个元素
我有一小部分固定节点: , , , .每个节点的值可以是 1 或 0。此外,每个节点的权重分别为:1、2、3、4。不使用节点属性。如何使用 XSLT 1.0 将每个节点的值乘以其权重相加?示例:
目前我在下面有一个数据集,如果 ColA 为 0,我尝试累加该值,而如果 ColA 再次为 1,则将值重置为 0(再次重新开始计数)。 ColA 1 0 1
我是一名优秀的程序员,十分优秀!