将数组中的低值归零的最快方法?
Posted
技术标签:
【中文标题】将数组中的低值归零的最快方法?【英文标题】:Fastest way to zero out low values in array? 【发布时间】:2010-12-10 01:53:58 【问题描述】:所以,假设我有 100,000 个浮点数组,每个数组包含 100 个元素。我需要最大的 X 个值,但前提是它们大于 Y。任何不匹配的元素都应该设置为 0。在 Python 中最快的方法是什么?必须维持秩序。大多数元素已经设置为 0。
样本变量:
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
预期结果:
array = [0, .25, 0, .15, .5, 0, 0, 0, 0, 0]
【问题讨论】:
highCountX 是我希望在数组中存在的最大非零元素数 如果是 2,预期结果将是:[0, 0, 0, .15, .5, 0, 0, 0, 0, 0] - highCountX 限制非零的数量结果中的元素。 如果值的个数超过highCountX,你如何选择保留哪一个扔掉 你保留最高值...如果有重复值,使用哪一个都没关系 @David:您应该考虑验证其中一个回复,以便告诉读者它确实解决了您的问题! 【参考方案1】:这是NumPy 的典型工作,对于这类操作来说非常快:
array_np = numpy.asarray(array)
low_values_flags = array_np < lowValY # Where values are low
array_np[low_values_flags] = 0 # All low values set to 0
现在,如果您只需要 highCountX 最大的元素,您甚至可以“忘记”小元素(而不是将它们设置为 0 并对其进行排序)而只对大元素列表进行排序:
array_np = numpy.asarray(array)
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:]
当然,如果您只需要几个元素,则对整个数组进行排序可能不是最佳选择。根据您的需要,您可能需要考虑标准的heapq 模块。
【讨论】:
很好...使用适当的库可以带你走得很远:-) 我一直遇到这个 numPy,我想我得检查一下 :) 感谢(大家)的帮助。 @David NumPy 确实满足了需求。我建议您从我链接到的教程开始:这可能是加快 NumPy 速度并学习其最重要概念的最快方式。 哪个更快:array_np[low_values_indices] = 0
或 array_np *= low_values_indices
?
假设您将 numpy 导入为 np ... 那么您也可以只使用 index = np.where(array
【参考方案2】:
from scipy.stats import threshold
thresholded = threshold(array, 0.5)
:)
【讨论】:
从 scipy 0.17.1 开始不推荐使用,请参阅 docs.scipy.org/doc/scipy-0.17.1/reference/generated/…【参考方案3】:NumPy 中有一个特殊的 MaskedArray 类可以做到这一点。您可以根据任何前提条件“屏蔽”元素。这比分配零更能代表您的需求:numpy 操作将在适当时忽略掩码值(例如,查找平均值)。
>>> from numpy import ma
>>> x = ma.array([.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0])
>>> x1 = ma.masked_inside(0, 0.1) # mask everything in 0..0.1 range
>>> x1
masked_array(data = [-- 0.25 -- 0.15 0.5 -- -- -- -- --],
mask = [ True False True False False True True True True True],
fill_value = 1e+20)
>>> print x.filled(0) # Fill with zeroes
[ 0 0.25 0 0.15 0.5 0 0 0 0 0 ]
另外一个好处是,如果您需要,matplotlib 可视化库很好地支持掩码数组。
Docs on masked arrays in numpy
【讨论】:
【参考方案4】:使用numpy
:
# assign zero to all elements less than or equal to `lowValY`
a[a<=lowValY] = 0
# find n-th largest element in the array (where n=highCountX)
x = partial_sort(a, highCountX, reverse=True)[:highCountX][-1]
#
a[a<x] = 0 #NOTE: it might leave more than highCountX non-zero elements
# . if there are duplicates
partial_sort
可能在哪里:
def partial_sort(a, n, reverse=False):
#NOTE: in general it should return full list but in your case this will do
return sorted(a, reverse=reverse)[:n]
表达式a[a<value] = 0
可以不用numpy
写成如下:
for i, x in enumerate(a):
if x < value:
a[i] = 0
【讨论】:
【参考方案5】:最简单的方法是:
topX = sorted([x for x in array if x > lowValY], reverse=True)[highCountX-1]
print [x if x >= topX else 0 for x in array]
这会选择所有大于lowValY
的元素:
[x for x in array if x > lowValY]
这个数组只包含大于阈值的元素个数。然后,对其进行排序,使最大值位于开头:
sorted(..., reverse=True)
然后列表索引取顶部highCountX
元素的阈值:
sorted(...)[highCountX-1]
最后,使用另一个列表推导式填充原始数组:
[x if x >= topX else 0 for x in array]
有一个边界条件,其中有两个或多个相等的元素(在您的示例中)是第三高的元素。结果数组将多次包含该元素。
还有其他边界条件,例如 iflen(array) < highCountX
。处理这些条件留给实现者。
【讨论】:
您可以使用 x for x in array if x > lowValY 而不是 [x for x in array if x > lowValY] 来枚举原始数组而不复制它(如果原始数据很大,这个可能是件好事)。 确实如此。不过,sorted()
可能还是需要整个列表。
嘿,比我的菜鸟代码快 3 倍,但我需要相等的元素来保持 highCountX 限制。数组应该有 20-200 个元素......它们实际上是我在块中处理的更大数组的片段。感谢您迄今为止的帮助。
我看不到你如何zero
ing 原始数组中的元素。
如果highCountX > len([x for x in array if x > lowValY])
那么你会得到IndexError。【参考方案6】:
将低于某个阈值的元素设置为零很容易:
array = [ x if x > threshold else 0.0 for x in array ]
(如果需要,偶尔加上 abs()。)
然而,N 个最大数的要求有点模糊。如果有例如怎么办?超过阈值的 N+1 个相等数?截断哪一个?
您可以先对数组进行排序,然后将阈值设置为第 N 个元素的值:
threshold = sorted(array, reverse=True)[N]
array = [ x if x >= threshold else 0.0 for x in array ]
注意:此解决方案针对可读性而非性能进行了优化。
【讨论】:
这种情况下,截断哪一个都无所谓……更重要的是后面跟highCountX【参考方案7】:你可以使用map和lambda,它应该足够快。
new_array = map(lambda x: x if x>y else 0, array)
【讨论】:
【参考方案8】:使用heap。
这可以及时O(n*lg(HighCountX))
。
import heapq
heap = []
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
for i in range(1,highCountX):
heappush(heap, lowValY)
heappop(heap)
for i in range( 0, len(array) - 1)
if array[i] > heap[0]:
heappush(heap, array[i])
min = heap[0]
array = [x if x >= min else 0 for x in array]
deletemin 在堆 O(lg(k))
和插入 O(lg(k))
或 O(1)
中工作,具体取决于您使用的堆类型。
【讨论】:
【参考方案9】:正如 egon 所说,使用堆是个好主意。但是您可以使用heapq.nlargest
函数来减少一些工作量:
import heapq
array = [.06, .25, 0, .15, .5, 0, 0, 0.04, 0, 0]
highCountX = 3
lowValY = .1
threshold = max(heapq.nlargest(highCountX, array)[-1], lowValY)
array = [x if x >= threshold else 0 for x in array]
【讨论】:
我喜欢这种只使用标准模块的自制解决方案。但是,应该升级它,以便真正返回最大的 highCountX 元素(如果数组中有很多元素的值threshold
,则最终数组中的非零元素太多)。以上是关于将数组中的低值归零的最快方法?的主要内容,如果未能解决你的问题,请参考以下文章
如果只需要结果的低位部分,哪些 2 的补码整数运算可以在不将输入中的高位归零的情况下使用?