Python - 生成一个包含 40 个随机数的列表,总和为 1,具有最小和最大权重
Python - Generate a list of 40 random numbers summing to 1, with min and max weight
我有一个包含 40 只股票的投资组合,我试图计算整个投资组合的标准差,同时每次计算这个标准差时都会更改每只股票的权重。我知道如何创建总和为 1 的随机数列表,但如何添加每只股票的最大和最小权重..
我使用的最大值是 4.5%,最小值是 0.5%。
我用来创建总和为 1 的随机数列表的代码是:
import numpy as np, numpy.random
random = np.random.dirichlet(np.ones(10), size=1)
但是我怎样才能使这个列表只包含 0.005 到 0.045 之间的值呢?
考虑使用以下内容:
import numpy as np
first_half = np.random.random(size=20)*0.04+0.005
second_half = 0.05-first_half
这是正确的范围,均匀分布,全部随机,但是,第二部分与第一部分(反)相关。您可以合并两半:
tot40elems = np.concatenate((first_half,second_half))
也许使用 np.random.normal 会得到更好的结果。您可以使用 80% 的可变比例(高于 0.005)将分布缩小到 0.005-0.045 范围。因为正态分布仍然可能有异常值,所以如果值超出范围,则有必要“重试”计算(但这不应该发生得太频繁,除非你给出一个大的标准偏差):
将 numpy 导入为 np
def randStock(count=40,minR=0.005,maxR=0.045,sd=3):
iterations = 0
while True:
iterations += 1
r = np.random.normal(1,sd,count) #normal distribution
r -= min(r) # offset to zero
r /= max(r) # scale to 0..1
r = minR + r/sum(r)*(maxR-minR)/(maxR+minR) # scale to range
if min(r)>=minR and max(r)<=maxR: return r, iterations
输出:
for _ in range(10):
s,i = randStock()
print(*map("{:6.4f}".format,(sum(s),min(s),max(s))),i,"iterations")
[sum] [min] [max] [mean]
1.0000 0.0050 0.0404 0.0250 1 iterations
1.0000 0.0050 0.0409 0.0250 2 iterations
1.0000 0.0050 0.0395 0.0250 1 iterations
1.0000 0.0050 0.0411 0.0250 4 iterations
1.0000 0.0050 0.0410 0.0250 2 iterations
1.0000 0.0050 0.0428 0.0250 1 iterations
1.0000 0.0050 0.0433 0.0250 1 iterations
1.0000 0.0050 0.0424 0.0250 1 iterations
1.0000 0.0050 0.0371 0.0250 1 iterations
1.0000 0.0050 0.0446 0.0250 1 iterations
请注意,这可以改进以随机化下限更多一点,您可以选择不同的标准偏差
我有一个包含 40 只股票的投资组合,我试图计算整个投资组合的标准差,同时每次计算这个标准差时都会更改每只股票的权重。我知道如何创建总和为 1 的随机数列表,但如何添加每只股票的最大和最小权重..
我使用的最大值是 4.5%,最小值是 0.5%。
我用来创建总和为 1 的随机数列表的代码是:
import numpy as np, numpy.random
random = np.random.dirichlet(np.ones(10), size=1)
但是我怎样才能使这个列表只包含 0.005 到 0.045 之间的值呢?
考虑使用以下内容:
import numpy as np
first_half = np.random.random(size=20)*0.04+0.005
second_half = 0.05-first_half
这是正确的范围,均匀分布,全部随机,但是,第二部分与第一部分(反)相关。您可以合并两半:
tot40elems = np.concatenate((first_half,second_half))
也许使用 np.random.normal 会得到更好的结果。您可以使用 80% 的可变比例(高于 0.005)将分布缩小到 0.005-0.045 范围。因为正态分布仍然可能有异常值,所以如果值超出范围,则有必要“重试”计算(但这不应该发生得太频繁,除非你给出一个大的标准偏差):
将 numpy 导入为 np
def randStock(count=40,minR=0.005,maxR=0.045,sd=3):
iterations = 0
while True:
iterations += 1
r = np.random.normal(1,sd,count) #normal distribution
r -= min(r) # offset to zero
r /= max(r) # scale to 0..1
r = minR + r/sum(r)*(maxR-minR)/(maxR+minR) # scale to range
if min(r)>=minR and max(r)<=maxR: return r, iterations
输出:
for _ in range(10):
s,i = randStock()
print(*map("{:6.4f}".format,(sum(s),min(s),max(s))),i,"iterations")
[sum] [min] [max] [mean]
1.0000 0.0050 0.0404 0.0250 1 iterations
1.0000 0.0050 0.0409 0.0250 2 iterations
1.0000 0.0050 0.0395 0.0250 1 iterations
1.0000 0.0050 0.0411 0.0250 4 iterations
1.0000 0.0050 0.0410 0.0250 2 iterations
1.0000 0.0050 0.0428 0.0250 1 iterations
1.0000 0.0050 0.0433 0.0250 1 iterations
1.0000 0.0050 0.0424 0.0250 1 iterations
1.0000 0.0050 0.0371 0.0250 1 iterations
1.0000 0.0050 0.0446 0.0250 1 iterations
请注意,这可以改进以随机化下限更多一点,您可以选择不同的标准偏差