配列の低い値をゼロにする最も速い方法は?
-
06-07-2019 - |
質問
つまり、それぞれ100個の要素を持つ100,000個のfloat配列があるとします。 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]
解決
これは 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の最大要素のみが必要な場合は、<!> quot; forget <!> quot;小さい要素(それらを0に設定して並べ替えるのではなく)と大きい要素のリストのみを並べ替えます:
array_np = numpy.asarray(array)
print numpy.sort(array_np[array_np >= lowValY])[-highCountX:]
もちろん、少数の要素のみが必要な場合に配列全体をソートすることは最適ではない場合があります。ニーズに応じて、標準の heapq モジュールを検討することをお勧めします。
他のヒント
from scipy.stats import threshold
thresholded = threshold(array, 0.5)
:)
NumPyには、まさにそれを行う特別なMaskedArrayクラスがあります。 <!> quot; mask <!> quot;前提条件に基づいた要素。これは、ゼロを割り当てるよりもニーズをよく表しています: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視覚化ライブラリでサポートされます。
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
は、次のように<=>なしで記述できます。
for i, x in enumerate(a):
if x < value:
a[i] = 0
最も簡単な方法は次のとおりです。
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]
(例では)3番目に高い要素である2つ以上の等しい要素がある境界条件があります。結果の配列には、その要素が複数回含まれます。
len(array) < highCountX
のような他の境界条件もあります。そのような条件の処理は実装者に任されています。
あるしきい値以下の要素をゼロに設定するのは簡単です:
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 ]
注:このソリューションは、パフォーマンスではなく読みやすさのために最適化されています。
mapとlambdaを使用できます。十分に高速でなければなりません。
new_array = map(lambda x: x if x>y else 0, array)
ヒープを使用します。
>これは時間内に動作します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(1)
または<=>で機能します。
エゴンが言うように、ヒープを使用するのは良い考えです。ただし、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]