基于Dirichlet分布的带权重边界的随机投资组合模拟问题求助
随机投资组合模拟约束问题的原因与解决方案
问题原因
你的代码生成的new_weights为空,核心原因是约束条件的可行域极小,随机抽样几乎不可能命中:
- 38个资产要求每个权重在
[0.02, 0.04]之间,同时总和必须为1。计算可得:- 所有资产的最小总权重:
38 * 0.02 = 0.76 - 所有资产的最大总权重:
38 * 0.04 = 1.52
- 所有资产的最小总权重:
- 虽然1落在这个区间内,但要让38个权重同时卡在
[0.02, 0.04]且总和为1,相当于要把剩余的0.24(1 - 0.76)精准分配到38个资产,每个最多加0.02。这种情况的概率极低,百万级别的随机样本完全抽不到符合条件的组合。
可行解决方案
不要用「随机抽样后筛选」的方式,直接生成满足约束的权重,步骤如下:
- 先给每个资产分配最小权重
0.02,此时总权重为0.76,剩余可分配额度为0.24; - 生成38个非负数,满足「总和为0.24」且「每个数≤0.02」(因为单个资产权重上限是
0.04,0.04-0.02=0.02); - 将生成的额外额度加到每个资产的最小权重上,得到最终符合约束的权重。
实现代码
import numpy as np n, width = 1000000, 38 min_weight = 0.02 max_weight = 0.04 remaining = 1 - width * min_weight # 剩余可分配额度:0.24 max_add = max_weight - min_weight # 单个资产最多可追加的额度:0.02 np.random.seed(5) # 先生成Dirichlet分布样本(天然满足总和为1),缩放后得到初始额外分配额度 dirichlet_samples = np.random.dirichlet(np.ones(width), size=n) extra = dirichlet_samples * remaining # 迭代调整,确保所有额外额度不超过max_add,同时总和保持为remaining while np.any(extra > max_add): # 计算每个样本中超过上限的部分 excess = extra - max_add excess[excess < 0] = 0 total_excess = excess.sum(axis=1, keepdims=True) # 找到未达上限的资产,计算可分配比例 mask = extra < max_add available = max_add - extra available[~mask] = 0 available_ratio = available / available.sum(axis=1, keepdims=True) # 把超额部分重新分配给未达上限的资产 extra[mask] += total_excess * available_ratio[mask] # 超过上限的部分直接设为max_add extra[extra > max_add] = max_add # 最终生成符合约束的权重 new_weights = min_weight + extra # 验证约束是否满足 assert np.all(new_weights >= min_weight) assert np.all(new_weights <= max_weight) assert np.allclose(new_weights.sum(axis=1), 1, atol=1e-6)
内容的提问来源于stack exchange,提问作者Dazz W
相关产品推荐
相关产品推荐

