我有一个程序需要一些大的NumPy数组,并且基于一些外部数据,通过向随机选择的单元格添加一个来增长它们,直到数组的总和等于外部数据。简化版和较小版本如下:
import numpy as np
my_array = np.random.random_integers(0, 100, [100, 100])
## Just creating a sample version of the array, then getting it's sum:
np.sum(my_array)
499097
所以,假设我想要增长数组,直到其总和为1,000,000,并且我想通过重复选择一个随机单元并向其添加1直到我们达到该总和为止这样做,我正在做类似的事情: / p>
diff = 1000000 - np.sum(my_array)
counter = 0
while counter < diff:
row = random.randrange(0,99)
col = random.randrange(0,99)
coordinate = [row, col]
my_array[coord] += 1
counter += 1
其中row / col组合返回数组中的随机单元格,然后该单元格增长1.它重复直到它将1添加到随机单元格的次数==原始区别之间的差异数组的总和和目标总和(1,000,000)。
然而,当我在运行之后检查结果时 - 总和总是关闭。在这种情况下,使用与上面相同的数字运行它之后:
np.sum(my_array)
99667203
我无法弄清楚是什么导致这种巨大的差异。是否有更多的pythonic方式来解决这个问题?
答案 0 :(得分:1)
my_array[coordinate]
没有达到您的预期。它正在选择多行并将1
添加到所有这些条目中。您只需使用my_array[row, col]
代替。
您可以简单地写一下:
for _ in range(1000000 - np.sum(my_array)):
my_array[random.randrange(0, 99), random.randrange(0, 99)] += 1
(如果使用Python 2.x,则为xrange
而不是range
答案 1 :(得分:0)
将my_array[coord]
替换为my_array[row][col]
。您的方法选择了两个随机整数,并且对应于两个整数的行中的每个条目都添加了1。
基本上你对numpy索引数组的方式有一点误解。
编辑:更清楚。 发布的代码选择了两个数字,比如30和45,并且在第30行的所有100个条目和第45行的所有100个条目中添加了1。
从这里你可以预期总和为100,679,697 = 200*(1,000,000 - 499,097) + 499,097
然而,当随机整数相同时(例如,45和45),只有1被添加到第45列的每个条目,而不是2,所以在这种情况下,总和只会跳过100。
答案 2 :(得分:0)
原始方法的问题在于您使用列表索引数组,该列表被解释为行维度中的索引序列,而不是行/列维度的单独索引(see here )。 尝试传递一个元组而不是列表:
coord = row, col
my_array[coord] += 1
更快的方法是找到输入数组的总和与目标值之间的差异,然后生成一个包含相同数量的随机索引的数组到数组中并一次性递增它们,从而避免循环在Python中:
import numpy as np
def grow_to_target(A, target=1000000, inplace=False):
if not inplace:
A = A.copy()
# how many times do we need to increment A?
n = target - A.sum()
# pick n random indices into the flattened array
idx = np.random.random_integers(0, A.size - 1, n)
# how many times did we sample each unique index?
uidx, counts = np.unique(idx, return_counts=True)
# increment the array counts times at each unique index
A.flat[uidx] += counts
return A
例如:
a = np.zeros((100, 100), dtype=np.int)
b = grow_to_target(a)
print(b.sum())
# 1000000
%timeit grow_to_target(a)
# 10 loops, best of 3: 91.5 ms per loop