Python 通过调整负项限制numpy数组中的项之和

Python 通过调整负项限制numpy数组中的项之和,python,arrays,performance,numpy,vectorization,Python,Arrays,Performance,Numpy,Vectorization,我有一个包含正数和负数的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(fin

我有一个包含正数和负数的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,-180110],本例中的答案是[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()
# 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()
案例2:

运行时测试-

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
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

这里是对先前提出的方法的一个稍微改进(代码更少,运行时更好)的版本-

# 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()
# 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