以最小增量加1的随机数:Matlab
仔细阅读了前面的问题 我正在努力解决一个类似但稍微复杂的问题 我想创建一个由n个元素组成的数组,其总和为1,但是我需要一个附加的约束,即每个元素的最小增量(或者如果您喜欢有效数字的数量)是固定的 例如,如果我想要10个和为1的数字,而不受任何约束,则以下操作非常有效:以最小增量加1的随机数:Matlab,matlab,random,Matlab,Random,仔细阅读了前面的问题 我正在努力解决一个类似但稍微复杂的问题 我想创建一个由n个元素组成的数组,其总和为1,但是我需要一个附加的约束,即每个元素的最小增量(或者如果您喜欢有效数字的数量)是固定的 例如,如果我想要10个和为1的数字,而不受任何约束,则以下操作非常有效: num_stocks=10; num_simulations=100000; temp = [zeros(num_simulations,1),sort(rand(num_simulations,num_stocks-1)
num_stocks=10;
num_simulations=100000;
temp = [zeros(num_simulations,1),sort(rand(num_simulations,num_stocks-1),2),ones(num_simulations,1)];
weights = diff(temp,[],2);
我愚蠢地认为,通过扩展它,我可以添加如下约束
num_stocks=10;
min_increment=0.001;
num_simulations=100000;
scaling=1/min_increment;
temp2 = [zeros(num_simulations,1),sort(round(rand(num_simulations,num_stocks-1)*scaling)/scaling,2),ones(num_simulations,1)];
weights2 = diff(temp2,[],2);
function weights = unbiased_monkey_weights(num_simulations,num_stocks,min_increment)
scaling=1/min_increment;
sample=NaN(num_simulations,num_stocks-1);
for i=1:num_simulations
allcomb=randperm(scaling+num_stocks-1);
sample(i,:)=allcomb(1:num_stocks-1);
end
temp = [zeros(num_simulations,1),sort(sample,2),ones(num_simulations,1)*(scaling+num_stocks)];
weights = (diff(temp,[],2)-1)/scaling;
end
然而,尽管这适用于小数值n和小数值增量,例如,如果n=1000,增量为0.1%,那么在大量试验中,第一个和最后一个数值的平均值始终低于0.1%
我确信对此有一个合乎逻辑的解释/解决方案,但我一直在竭尽全力尝试并找到它,不知道有谁会好心地为我指出正确的方向。将问题置于上下文中,创建随机股票组合(因此总和为1)
提前谢谢
感谢您到目前为止的回复,只是为了澄清一下(因为我认为我最初的问题可能措词不当),权重的固定增量为0.1%,即0.0%、0.1%、0.2%等等
起初我确实尝试过使用整数
num_stocks=1000;
min_increment=0.001;
num_simulations=100000;
scaling=1/min_increment;
temp = [zeros(num_simulations,1),sort(randi([0 scaling],num_simulations,num_stocks-1),2),ones(num_simulations,1)*scaling];
weights = (diff(temp,[],2)/scaling);
test=mean(weights);
但更糟糕的是,第一次和最后一次重量的平均值远低于0.1%
编辑以反映Floris&Clearify的优秀答案
我用来解决这个问题的原始代码(在找到这个论坛之前)是
这运行速度非常快,这很重要,因为我想运行10000000个模拟,1000个股票上的10000个模拟只需2秒钟,使用一个单核&我正在使用并行工具箱在8核机器上运行整个代码
它也给出了我一直在寻找的均值分布,我认为得到一只股票100%的投资组合的可能性与得到一只股票0.1%的投资组合的可能性一样(尽管我很高兴被纠正)
我的问题是,尽管它适用于1000只股票,增量为0.1%,我猜它适用于100只股票,增量为1%,但随着股票数量的减少,每个选择都会变成一个非常大的百分比(在极端情况下,2只股票的投资组合总是50/50)
实际上,我认为这个解决方案与Floris建议的二项式解决方案类似(但更为有限)
然而,我的问题出现了,因为我想让我的方法更灵活,有可能是3支股票,1%的增量,而我目前的代码无法正确处理,因此我无意中接受了关于stackoverflow的原始问题
Floris的递归方法将得到正确的答案,但考虑到问题的规模,速度将是一个主要问题
这里是原始研究的一个例子
我目前正在努力扩展它,使其在投资组合权重和指数中的股票数量方面具有更大的灵活性,但似乎我的编程和概率论能力是一个限制因素……我可以看到的一个问题是,你的公式允许数字为零——当四舍五入操作导致排序后两个连续数字相同时。不确定你是否认为这是一个问题-但我建议你考虑一下(这意味着你的模型投资组合中有少于N个股票,因为其中一个股票的贡献将是零)。p> 另一件需要注意的事情是,在分布中得到极值的概率是你想要的概率的一半:如果你有从0到1000的均匀分布的数字,并且你对它们进行
四舍五入
,四舍五入到0
的数字在区间[0.5>
;四舍五入到1
的数字来自[0.5 1.5>
——两倍大。最后一个数字(四舍五入到1000
)的间隔也更小:[999.5 1000]
。因此,你不会像你想象的那样经常得到第一个和最后一个数字。如果你不使用轮
而是使用楼层
我想你会得到你期望的答案
编辑
我对此进行了更多的思考,并提出了一种缓慢但(我认为)准确的方法。基本思想如下:
(N/m)
的二元分布变量-调用第一个值v1
;然后将剩余区间N-v1
划分为m-1
步骤;我们可以递归地这样做% random integers adding up to a definite sum
function r = randomInt(n, limit)
% returns an array of n random integers
% whose sum is limit
% calls itself recursively; slow but accurate
if n>1
v = binomialRandom(limit, 1 / n);
r = [v randomInt(n-1, limit - v)];
else
r = limit;
end
function b = binomialRandom(N, p)
b = sum(rand(1,N)<p); % slow but direct
这在一台普通的机器(单线程)上运行了3.8秒——当然,获取二元分布随机变量的方法会减慢速度;有一些统计工具箱具有更高效的函数,但我没有。如果您增加粒度(例如,通过设置limit=10000
)由于您增加了生成的随机数样本的数量,因此速度会更慢;当limit=10000
时,上述循环需要13.3秒才能完成
作为一项测试,我发现平均值(投资组合)
和标准值(投资组合)
如下所示(其中限值=1000
):
对我来说,这看起来像是一个非常令人信服的“平坦”分布。我们期望数字以平均值100的二元分布,标准偏差为sqrt(p*(1-p)*n)
。在这种情况下,p=0.1
,因此我们期望
tic
portfolio = zeros(10000, 10);
for ii = 1:10000
portfolio(ii,:) = randomInt(10, 1000);
end
toc
100.20 9.446
99.90 9.547
100.09 9.456
100.00 9.548
100.01 9.356
100.00 9.484
99.69 9.639
100.06 9.493
99.94 9.599
100.11 9.453
X = diff([0,sort(rand(1,10)),1]*45);
Y = X + 5;
function weights = unbiased_monkey_weights(num_simulations,num_stocks,min_increment)
scaling=1/min_increment;
sample=NaN(num_simulations,num_stocks-1);
for i=1:num_simulations
allcomb=randperm(scaling+num_stocks-1);
sample(i,:)=allcomb(1:num_stocks-1);
end
temp = [zeros(num_simulations,1),sort(sample,2),ones(num_simulations,1)*(scaling+num_stocks)];
weights = (diff(temp,[],2)-1)/scaling;
end