我有增加和减少浮点值的列表:
如图所示,这些值可能会增加或减少,并且可能会突然重置为 接近零值。我想确切地知道这些值在哪里重置为接近零值。
我尝试过这样的事情:
# input list of floats
# floats = [...]
# find the absolute difference between consecutive values
diff_floats = [abs(floats[i] - floats[i-1]) for i in range(1, len(floats))]
# Sort the list in descending order
sorted_diff_floats = sorted(diff_floats, reverse=True)
# Calculate the average of the top 14 differences
threshold = sum(sorted_diff_floats[:14]) / 14
# Count the number of values greater than the threshold
print(len([value for value in diff_floats if value > threshold]))
我硬编码了
14
,因为我知道根据经验重置不会发生超过 7 次。因此最好获得前 14 个差异的平均值,而不是所有值的平均值。
我还没有获得这些重置的索引,我可以通过修改代码的最后一行轻松获得这些索引。但我觉得逻辑仍然可以改进,可以在任何浮点数输入列表上工作,而不需要考虑 7 次重置的经验知识。
通用的解决方案是什么?
“突然重置到接近零”的概念可供解释;就像什么时候移动不再那么突然,什么时候值不够接近零。
但这里有一个你可以使用的想法:
仅考虑大于差异的中位数的差异,然后仅考虑“接近零”那些与零之差小于中位数的值:
jumps = [i
for i, (diff, val) in enumerate(zip(diff_floats, floats[1:]), start=1)
if diff > median_diff > abs(val)
]
每当我看到“算法”标签以及语言标签(此处为“python”)时,我就认为使用伪代码是可以接受的。我将用 Ruby 提供答案,它可以作为伪代码阅读,并在需要时提供帮助和解释。
让我们举个例子。 (我将使用整数,但如果值是浮点数,代码是相同的。)假设:
x = [4, 3, 0, -1, -2, 0, 2, 1, 0, -4]
可以绘制如下图:
4 x
3 x
2 x
1 x
0 x x x
-1 x
-2 x
-3
-4 x
0 1 2 3 4 5 6 7 8 9
接下来,通过任何认为合适的方式定义一个阈值,如果该值等于零且等于
中前一个或后一个值的绝对值,则可以(通过其索引)识别
x
的元素x
大于或等于阈值。
假设:
threshold = 3
现在让:
a1 = x.each_index.each_cons(3).to_a
#=> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5],
# [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9]]
这个计算如何运作并不重要,重要的是产生什么,这应该是显而易见的。
[1, 2, 3]
,例如,包含数组 1
中的索引 2
、3
和 x
。
继续,
a2 = a1.select do |e1, e2, e3|
x[e2] == 0 and (x[e1].abs >= threshold or x[e3].abs >= threshold)
end
#=> [[1, 2, 3], [7, 8, 9]]
最后,
a2.map { |e1, e2, e3| e2 } # or a2.map { |a| a[1] }
#=> [2, 8]
这表明索引
x
和 2
(但不在 8
)处的 5
零值已被识别。