gpt4 book ai didi

Python - 生成符合条件的大型集合组合的最有效方法?

转载 作者:行者123 更新时间:2023-11-28 16:29:16 25 4
gpt4 key购买 nike

我试图在受边界条件约束的投资组合中生成所有可能的金融工具组合。

例如,假设我有一组列表,这些列表代表对投资组合的分配,每个工具受总投资组合规模的最小和最大百分比限制:

"US Bonds" = {0.10,0.15,0.20,0.25,0.30}
"US Equities" = {0.25, 0.30, 0.35, 0.40, 0.45, 0.50}
"European Bonds" = {0.10, 0.15, 0.20}
"European Equities = {0.20,0.25,0.30,0.35,0.40,0.45,0.50}
...
"Cash" = {0.0, 0.05, 0.10, 0.15,...0.95}

我的 list 、 Assets 如下所示:

[In]
Asset

[Out]
[[0.1, 0.15, 0.2, 0.25, 0.30],
[0.25, 0.30,0.35, 0.40, 0.45, 0.50],
[0.1, 0.15, 0.2],
[0.20, 0.25, 0.30,0.35, 0.40, 0.45, 0.50]
...
[0.0, 0.05, 0.1, 0.15, 0.2, 0.25,...0.95]]

根据每个工具组合的总和必须 = 1 的标准,生成所有可能的投资组合的最有效方法是什么?

现在,我正在创建一个“投资组合”列表,如下所示:

portfolios  = [item for item in itertools.product(*asset) if  np.isclose(sum(item),1)]

(nb,'np.isclose' 处理时髦的 fp 算术)。

我已经将 Assets 类别和可能的分配表示为列表的集合,但想知道是否有不同的数据表示(例如,NumPY 数组)会更快。

有一些关于各种组合的最佳执行的问题,但我没有看到有任何边界条件的问题。

最佳答案

(注意:代码位于:http://lpaste.net/145213)

首先,我会将百分比表示为整数值以避免浮点舍入错误。

其次,最有效的方法是使用边界来避免查看不可能满足 == 1 约束的投资组合。

您要编写的循环将像这样运行:

def portfolios():
for us_bonds in [ 10, 15, 20, 25, 30 ]:
if us_bonds > 100: break
for us_equaties in [ 25, 30, 35, 40, 45, 50 ]:
if us_bonds + us_equaties > 100: break
for euro_bonds in [ 10, 15, 20 ]:
if us_bonds + us_equaties + euro_bonds > 100: break
for euro_equaties in [ 20, 25, 30, 35, 40, 45, 50 ]:
if us_bonds + us_equaties + euro_bonds + euro_equaties > 100: break
cash = 100 - (us_bonds + us_equaties + euro_bonds + euro_equaties)
yield [us_bonds, us_equaties, euro_bonds, euro_equaties, cash]

这定义了一个生成器,您可以像这样在 for 循环中使用它:

for x in portfolios(): print x

这种方法是有效的,因为它避免了构建超过 == 100 限制的投资组合。

另请注意,我们利用了“现金”百分比基本上可以是任何东西这一事实 - 因此它只占 100% 与其他投资类别总数之间的差额。

以下函数将此循环概括为任意数量的投资类别:

def gen_portfolio(categories):
n = len(categories)
tarr = [0] * (n+1)
parr = [0] * (n+1)
karr = [0] * (n+1)
marr = [ len(c) for c in categories ]
i = 0
while True:
while True:
if i < n:
p = categories[i][ karr[i] ]
t = tarr[i] + p
if t <= 100:
parr[i] = p
tarr[i+1] = t
i += 1
karr[i] = 0
continue
else:
break # backup
else:
parr[n] = 100 - tarr[n] # set the Cash percentage
yield parr[:] # yield a copy of the array parr
break
# backup
while True:
if i > 0:
i -= 1
karr[i] += 1
if karr[i] < marr[i]: break
else:
return # done!

def portfolios2():
cats = [ [ 10, 15, 20, 25, 30 ], [ 25, 30, 35, 40, 45, 50 ], [ 10, 15, 20 ], [ 20, 25, 30, 35, 40, 45, 50 ] ]
return gen_portfolio(cats)

这里有一个测试表明它们产生了相同的结果:

def compareTest():
ports1 = [ x for x in portfolios() ]
ports2 = [ x for x in portfolios2() ]
print "ports1 length:", len(ports1)
print "ports2 length:", len(ports2)
for x in ports1:
if x not in ports2: print "not in ports2:", x
for x in ports2:
if x not in ports1: print "not in ports1:", x

更新

下面是一个示例,演示了此方法与 itertools.product 之间的区别。

假设有 10 个投资类别,每个类别的百分比为 [90,91,..,99]。带有 break 语句的嵌套循环将按如下方式进行:

start the loop: for p1 in [90,91,..,99]

set p1 = 90
p1 < 100 so continue

start the loop: for p2 in [90,91,..,99]
set p2 = 90
p1 + p2 > 100, so break out of the p2 loop

set p1 = 91

p1 < 100 so continue
start the loop: for p2 in [90,91,..,99]
set p2 = 90
p1 + p2 > 100, so break out of the p2 loop
set p1 = 92
...

所以带有 break 语句的嵌套循环只查看 10 种情况 - p1 = 90, 91, .., 99 和 p2 = 90。p2 永远不会大于 90 并且它永远不会尝试将任何东西分配给 p3,p4, ...,第 10 页。

另一方面,itertools.product 将生成所有 100 个案例,然后您必须过滤掉那些总和 > 100 的组合。

对于某些输入,itertools.product 可能更快,因为它是用 C 编写的,但它不会根据当前选择的总和对案例进行任何修剪。

关于Python - 生成符合条件的大型集合组合的最有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33704780/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com