[英]Limit sum of entries in numpy array by adjusting negative entries
我有一個包含正值和負值的 numpy 數組,我想調整負條目,使總和不為負,從最負的條目開始。 最大的調整是使負條目為零。 我有一個使用循環的實現,有沒有辦法使用 numpy 數組方法來實現? 這是我的代碼:
initial_values = np.asarray([50,-200,-180,110])
sorted_index = np.argsort(initial_values)
final_values = initial_values
for i, entry in enumerate(final_values[sorted_index]):
ss = final_values.sum()
if ss >= 0:
break
adjustment = max(entry, ss)
final_values[sorted_index[i]] -= adjustment
print final_values
起始數組是[50,-200,-180,110],本例的答案是[50, 0, -160, 110],所以最負的條目設置為零,然后調整下一個最負的條目使總和為零。
有沒有人有更簡單、更快的基於 numpy 的解決方案?
這是一種矢量化方法 -
# Get a copy of input as the output
out = initial_values.copy()
# Get sorted indices
sorted_index = np.argsort(out)
# Mask of elements that would be made zero for sure and zero them
mask = out.sum() < out[sorted_index].cumsum()
out[sorted_index[mask]] = 0
# There might be one element left to make the sum absolutely zero.
# Make it less negative to make the absolute sum zero.
out[sorted_index[np.where(mask)[0][-1]+1]] -= out.sum()
樣品運行 -
函數定義 -
In [155]: def vectorized(initial_values):
...: out = initial_values.copy()
...: sorted_index = np.argsort(out)
...: mask = out.sum() < out[sorted_index].cumsum()
...: out[sorted_index[mask]] = 0
...: out[sorted_index[np.where(mask)[0][-1]+1]] -= out.sum()
...: return out
...:
...: def org_app(initial_values):
...: final_values = initial_values.copy()
...: sorted_index = np.argsort(initial_values)
...: for i, entry in enumerate(final_values[sorted_index]):
...: ss = final_values.sum()
...: if ss >= 0:
...: break
...: adjustment = max(entry, ss)
...: final_values[sorted_index[i]] -= adjustment
...: return final_values
...:
情況1 :
In [156]: initial_values
Out[156]: array([ 50, -200, -180, 110])
In [157]: vectorized(initial_values)
Out[157]: array([ 50, 0, -160, 110])
In [158]: org_app(initial_values)
Out[158]: array([ 50, 0, -160, 110])
案例#2:
In [163]: initial_values
Out[163]: array([ 50, -20, -14, -22, -15, 6, -21, -19, -17, 4, 5, -56])
In [164]: vectorized(initial_values)
Out[164]: array([ 50, 0, -14, 0, -15, 6, 0, -19, -17, 4, 5, 0])
In [165]: org_app(initial_values)
Out[165]: array([ 50, 0, -14, 0, -15, 6, 0, -19, -17, 4, 5, 0])
運行時測試 -
In [177]: initial_values = np.random.randint(-100,20,(50000))
In [178]: np.array_equal(vectorized(initial_values),org_app(initial_values))
Out[178]: True
In [179]: %timeit org_app(initial_values)
1 loops, best of 3: 2.08 s per loop
In [180]: %timeit vectorized(initial_values)
100 loops, best of 3: 5.7 ms per loop
這是較早提出的方法的略微改進(更少的代碼和更好的運行時)版本 -
# Get a copy of input as the output
out = initial_values.copy()
# Get sorted indices
sorted_index = np.argsort(out)
# Last index in sorted indexed indices for setting elements in input array to 0's
idx = np.where(out.sum() < out[sorted_index].cumsum())[0][-1]
# Set until idx indexed into sorted_index in turn indexed into input array t0 0's
out[sorted_index[:idx+1]] = 0
# There might be one element left to make the sum absolutely zero.
# Make it less negative to make the absolute sum zero.
out[sorted_index[idx+1]] -= out.sum()
運行時測試 -
In [18]: initial_values = np.random.randint(-100,20,(50000))
In [19]: %timeit vectorized(initial_values)
100 loops, best of 3: 5.58 ms per loop
In [20]: %timeit vectorized_v2(initial_values) # improved version
100 loops, best of 3: 5.4 ms per loop
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.