动态规划之投资问题python实现多次优化

投资分配问题

现有数量为a(万元)的资金,计划分配给n 个工厂,用于扩大再生产。
假设:
xi 为分配给第i 个工厂的资金数量(万元);
gi(xi)为第i 个工厂得到资金后提供的利润值(万元)。
  问题:如何确定各工厂的资金数,使得总的利润为最大。
下表为各工厂获得投资后可以产生的利润:

利润\投资0102030405060
g1(x)0205065808585
g2(x)0204050556065
g3(x)0256085100110115
g4(x)0254050606570

问题分析

根据上述的问题可知我们需要求解最大的目标收益Z
问题表示
用fk(x) 表示 以数量为 x 的资金分配给前k 个工厂,所得到的最大利润值。
用动态规划求解,就是求 fn(a) 的问题。

当K=1时,

1-1
当1<K≤𝒏时,
1-2

代码设计

数据初始化

由于这里是一个mn的二维表,所以采用一个二维列表values(维度:47)来存储各个工厂接受投资后产生的收益

values = [
    [0, 20, 50, 65, 80, 85, 85],
    [0, 20, 40, 50, 55, 60, 65],
    [0, 25, 60, 85, 100, 110, 115],
    [0, 25, 40, 50, 60, 65, 70]
]

函数设计

  1. 动态规划函数,
  • 在动态规划函数中,首先获取投资项目数以及投资金额数目。
  • 构造一个三维列表(4X7X4)s和一个二维列表(4X7)dp,来分别存储最优投资组合和对应的投资组合的收益。
  • 函数具体实现是通过一个三层for循环结构,外面两层for循环是遍历二维列表s,dp的,第三个for循环是实现寻找上一次组合和这一次的投资项目与进行新的组合的最大值。
    值的注意的是下面的这行
s[i][j] = s[i - 1][j - k].copy()

这里涉及到python列表的直接赋值是引用赋值,所以为了避免引用赋值而导致的程序错误,这里使用了浅拷贝来完成对数组的复制

# 实现动态规划的函数
def invest_f(values):
    m = len(values)  # 投资项目数
    n = len(values[0])  # 投资金额
    dp = [[0 for i in range(n)] for j in range(m)]
    s = [[[0] for i in range(n)] for j in range(m)]

    for i in range(m):
        for j in range(n):
            if i == 0:
                dp[i][j] = values[i][j]
                s[i][j] = [j * 10]
            else:
                for k in range(j + 1):
                    if dp[i][j] < dp[i - 1][j - k] + values[i][k]:
                        dp[i][j] = dp[i - 1][j - k] + values[i][k]
                        s[i - 1][j - k].append(k * 10)
                        s[i][j] = s[i - 1][j - k].copy()
                        s[i - 1][j - k].pop()
    return dp, s
  1. 为了使得矩阵输出得比较好看,这里单独写了一个矩阵输出函数
# 矩阵输出的更加好看
def print_matrix(p):
    print("[")
    for i in range(len(p)):
        print(p[i])
    print("]")
  1. 函数调用以及结果输出
dp, s = invest_f(values)
print("最大的投资收益矩阵为:")
print_matrix(dp)
print("最大的投资组合矩阵为:")
print_matrix(s)
print("最大的投资收益为:", dp[-1][-1])

问题最优化结果

结果-1
动手计算

投资分配问题代码错误改进

从上述两张表中对比可以发现:
在求F4(x)的时候,代码显示的F4(x)策略是[0,10,0]而最终问题的答案却是[0,0,10,0]

在代码中显示的[0,10,0]的意思应理解为,

  • 第一,三,四项目均为投0元,第二个项目投10万元

而根据手动计算得知应为[0,0,10,0]

  • 第一,二,四项目均为投0元,第三个项目投10万元

函数重构

在原有的基础上,添加了一个f标志,记录在k循环过程中。
是否添加了元素进入列表,若没有添加新元素,需要补0操作

def invest_f(values):
    m = len(values)  # 投资项目数
    n = len(values[0])  # 投资金额
    dp = [[0 for i in range(n)] for j in range(m)]
    s = [[[0] for i in range(n)] for j in range(m)]

    for i in range(m):
        for j in range(n):
            if i == 0:
                dp[i][j] = values[i][j]
                s[i][j] = [j * 10]
            else:
                f = 0
                for k in range(1, j + 1):
                    if dp[i][j] < dp[i - 1][j - k] + values[i][k]:
                        f += 1
                        dp[i][j] = dp[i - 1][j - k] + values[i][k]
                        s[i - 1][j - k].append(k * 10)
                        s[i][j] = s[i - 1][j - k].copy()
                        s[i - 1][j - k].pop()
                if f == 0:
                    s[i - 1][j - k].append(0)
                    s[i][j] = s[i - 1][j - k].copy()
                    s[i - 1][j - k].pop()
    return dp, s

结果对比

结果-2

手动计算
由上图对比可知,重构后代码与手动计算结果已经一样了

投资问题代码优化

优化分析

实际上我们需要的只是最后的投资方案以及对应的投资收益而已,那么我们其实只需要记录添加第i个项目时的最优投资方案以及最大收益和第i-1个项目的最优投资方案以及最大收益。

那么如何实现只有添加第i个项目和第i-1个项目的结果呢?

  1. 双列表
    第一个列表记录第i-1个项目的结果,第二个列表记录第i个项目的结果。然后再将第i个项目的结果值引用赋值给第1个列表,然后i++,实现下层迭代计算。
    这样的话可以将原有的二维列表dp,三维列表s的各维度分别由原来的(4X7)和(4X7X4)降至(2X7)和(2X7X4)
    这里我偷懒一下我觉得这种方法没有第二种方法好,所以没有具体实现。
  2. 第二层for循环从后至前遍历
    根据问题分析里面的递推公式可知
    当K=1时,

1-1
当1<K≤𝒏时,
1-2
当添加第k个项目且当前投资为jX10时,该项目的最优方案计算,只与添加第k-1个项目的前j个值有关。
从后往前遍历,当更新dp[j]时,dp[1],dp[2],…,dp[j-1]都是未更新的,也就是添加第i-1个项目时的最优值,根据未更新的dp[1],dp[2],…,dp[j-1]来更新dp[j],然后j–,更新下一个dp[j]
这样我们就可以再次将s,dp进行简化。将原本的三维(4X7X4)的s列表精简至二维的(7X4)列表,将二维的(4X7)精简为的一维的含有7元素的列表。

具体修改后的代码如下所示:

def invest_f(values):
    n = len(values)
    m = len(values[0])
    dp = [0 for _ in range(m)]
    s = [[0] for _ in range(m)]
    for i in range(n):
        for j in range(m - 1, -1, -1):
            if i == 0:
                dp[j] = values[i][j]
                s[j] = [j * 10]
            else:
                f = 0
                for k in range(j, 0, -1):
                    if dp[j] < dp[j - k] + values[i][k]:
                        f += 1
                        dp[j] = dp[j - k] + values[i][k]
                        s[j - k].append(k * 10)
                        s[j] = s[j - k].copy()
                        s[j - k].pop()
                if f == 0:
                    s[j].append(0)
    return dp, s

更改后的函数调用以及输出

# 将各工厂投资0-5万的收益放进一个二维数组
values = [
    [0, 20, 50, 65, 80, 85, 85],
    [0, 20, 40, 50, 55, 60, 65],
    [0, 25, 60, 85, 100, 110, 115],
    [0, 25, 40, 50, 60, 65, 70]]
dp, s = invest_f(values)
print("最大的投资收益矩阵为:\n", dp)
print("最大的投资组合矩阵为:\n")
print_matrix(s)
print("最大的投资收益为:{0}\n最大的投资组合:{1}".format(dp[-1], s[-1]))

结果对比

结果-3
手动计算
由于我这一次的dp列表和s只存储了最后的方案,所以前几项的方案都看不了。
但是最后一行的结果是绝对正确的。

总结

问题

  1. python列表的引用传递产生的问题
  2. 投资组合更新时的未找到k时产生的组合数缺失

解决办法

  1. 使用python列表的浅拷贝函数
  2. 创建变量f,标志在k循环中,是否找到合适的k。若没有找到则执行在对应的投资组合中进行补0操作
  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Python量化投资遗传规划是指使用Python编程语言来进行量化投资,并结合遗传规划算法。量化投资是利用数学模型和统计方法,通过系统性的策略进行投资决策的一种方式。而遗传规划是一种优化算法,模拟自然界中基因遗传和演化的过程,通过基因操作和选择适应度的方式,寻找最优解。 在量化投资中,使用Python编程语言有着许多优势。首先,Python具有简洁灵活的语法和强大的数据处理能力,适合处理大量的金融数据。其次,Python拥有丰富的第三方库和工具,如NumPy、Pandas和Matplotlib等,可方便地进行数据分析和可视化。此外,Python还具有跨平台特性,可以在不同操作系统上运行,并且有着庞大的开源社区支持。 将遗传规划算法应用于量化投资中,可以通过模拟基因的变异、交叉和选择过程,来寻找最优的投资策略参数组合。遗传规划算法通过多次的迭代计算、随机生成和优胜劣汰的过程,逐步优化投资策略,从而提高投资的效益和稳定性。 在使用Python进行量化投资遗传规划时,首先需要定义适应度函数,用于评估投资策略的好坏程度。然后,利用遗传规划算法生成初始种群,并通过基因操作和选择适应度的方式,逐步优化种群,最终找到最优解。最后,根据最优解构建量化投资策略,并实施实时的交易操作。 总之,Python量化投资遗传规划是一种将量化投资与遗传规划算法相结合的方法,可以通过编程语言和优化算法找到最佳投资策略。利用Python的强大功能和丰富工具,能够更高效地进行数据处理和分析,从而提高投资决策的准确性和效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值