如果总和为1,我可以将这些值除以总和。但是,当总和为0时,此方法不适用。
也许我可以计算每个采样值的相反值,所以我总是会有一对数字,使得它们的总和为0。但是,这种方法减少了我希望在随机数组中拥有的“随机性”。
有更好的方法吗?
编辑:数组的长度可以变化(从3到几百个),但是在采样之前必须固定。
答案 0 :(得分:1)
有一个 Dirichlet-Rescale (DRS) algorithm 可以生成随机数总和为给定的数字。正如它所说,它具有
<块引用>向量均匀分布在有效区域上 所有可能向量的域,受约束。
它还有一个 Python library。
答案 1 :(得分:0)
我会尝试以下解决方案:
def draw_randoms_while_sum_not_zero(eps):
r = random.uniform(-1, 1)
sum = r
yield r
while abs(sum) > eps:
if sum > 0:
r = random.uniform(-1, 0)
else:
r = random.uniform(0,1)
sum += r
yield r
由于浮点数不是十分准确,所以您永远无法确定要绘制的数字总和为0。您需要确定可接受的边距,然后调用上述生成器。
只要不等于0 ± eps
,它就会根据您的需要产生(延迟返回)随机数
epss = [0.1, 0.01, 0.001, 0.0001, 0.00001]
for eps in epss:
lengths = []
for _ in range(100):
lengths.append(len(list(draw_randoms_while_sum_not_zero(eps))))
print(f'{eps}: min={min(lengths)}, max={max(lengths)}, avg={sum(lengths)/len(lengths)}')
结果:
0.1: min=1, max=24, avg=6.1
0.01: min=1, max=174, avg=49.27
0.001: min=4, max=2837, avg=421.41
0.0001: min=5, max=21830, avg=4486.51
1e-05: min=183, max=226286, avg=48754.42
答案 2 :(得分:0)
生成此类列表的一种方法是使用相反的数字。 如果这不是理想的属性,则可以通过向不同的相反对添加/减去相同的随机值来引入一些额外的随机性,例如:
No module named 'lib'
如果上限和下限不是严格的,构造零和序列的一种简单方法是将两个单独的序列求和归一化为1和-1并将它们连接在一起:
def exact_sum_uniform_random(num, min_val=-1.0, max_val=1.0, epsilon=0.1):
items = [random.uniform(min_val, max_val) for _ in range(num // 2)]
opposites = [-x for x in items]
if num % 2 != 0:
items.append(0.0)
for i in range(len(items)):
diff = random.random() * epsilon
if items[i] + diff <= max_val \
and any(opposite - diff >= min_val for opposite in opposites):
items[i] += diff
modified = False
while not modified:
j = random.randint(0, num // 2 - 1)
if opposites[j] - diff >= min_val:
opposites[j] -= diff
modified = True
result = items + opposites
random.shuffle(result)
return result
random.seed(0)
x = exact_sum_uniform_random(3)
print(x, sum(x))
# [0.7646391433441265, -0.7686875811622043, 0.004048437818077755] 2.2551405187698492e-17
请注意,两种方法通常都不会具有统一的分布。
答案 3 :(得分:0)
您可以使用sklearns Standardscaler。它会将您的数据缩放为方差为1,平均值为0。平均值为0等于总和为0。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np
rand_numbers = StandardScaler().fit_transform(np.random.rand(100,1, ))
如果您不想使用sklearn,则可以手动进行标准化,该公式非常简单:
rand_numbers = np.random.rand(1000,1, )
rand_numbers = (rand_numbers - np.mean(rand_numbers)) / np.std(rand_numbers)
这里的问题是1的方差,它导致数字大于1或小于-1。因此,您可以通过其最大abs值来定义数组。
rand_numbers = rand_numbers*(1/max(abs(rand_numbers)))
现在您有了一个数组,其值介于-1和1之间,总和实际上接近于零。
print(sum(rand_numbers))
print(min(rand_numbers))
print(max(rand_numbers))
输出:
[-1.51822999e-14]
[-0.99356294]
[1.]
此解决方案将使您的数据始终保持1或1 -1的状态。如果您想避免这种情况,可以通过最大吸收将正随机因子添加到除法中。 rand_numbers*(1/(max(abs(rand_numbers))+randomfactor))
修改
正如@KarlKnechtel所提到的,用标准偏差进行除法与用最大绝对值进行除法是多余的。
以上操作可以通过以下方式简单完成:
rand_numbers = np.random.rand(100000,1, )
rand_numbers = rand_numbers - np.mean(rand_numbers)
rand_numbers = rand_numbers / max(abs(rand_numbers))
答案 4 :(得分:0)
由于您可以生成大量数字并除以和,所以为什么不生成n / 2个正数除以和。然后生成n / 2个负数并除以和?
是否需要从正到负的随机组合?首先随机生成该混合,然后继续。