穷举法带来未知结果,求分析原因

问题:采用穷举法,产生包含5个整数的一个数组作为输入,记录下最优的输出值和对应的数组。但是穷举法产生的输出值和直接输入该数组得到的结果不能对应。
代码:
穷举法的代码(loc[0,]即为输入数组的位置):

for i in range(1, 39, 1):  
    for j in range(1, 39 - i, 1):
        for k in range(1, 39 - i - j, 1):
            for p in range(1, 39 - i - j - k, 1):
                if 39 - i - j - k - p >= 0:
                    Market_data2 = MARKET_DATA
                    Pe_series = [0, 5 + i, 5 + i + j, 5 + i + j + k, 5 + i + j + k + p]  
                    Pe_data.loc[0, ] = Pe_series 
                    Pe_dict = form_position_pe_rules(Pe_data)
                    Pe_array = position_rules_array(Pe_dict)
                    Market_data2 = scan_data(Market_data2, TRADE_RULES, INITIAL_FUND, Pe_dict, Pe_array)
                    CAGR = pow(Market_data2.iloc[-1][8] / INITIAL_FUND,
                               1 / ((Market_data2.iloc[-1][0] - Market_data2.iloc[0][0]).days / 365.25)) - 1
                    if CAGR > BEST_CAGR:
                        BEST_CAGR = CAGR
                        Best_pe_data = Pe_data
                        Best_market_data = Market_data2
                else:
                    break
print("The CAGR is: " + "{:%}".format(BEST_CAGR))
print("The BEST POSITION_PE_RULE is: ")
print(Best_pe_data)

得到输出如下(index[0]即为该数组):

The CAGR is: 11.872823%
The BEST POSITION_PE_RULE is: 
  a0   a1   a2   a3   a4
0  0   40   41   42   43
1  1  0.8  0.6  0.4  0.2
The programme takes 35189.463971138 s.

Process finished with exit code 0

可以看出,在数组为[0,40,41,42,43]的时候(对应i为35,j,k,p为1)取到最优值11.87%,但是,如果不用穷举法,直接输入数组,得到的最优值并不一致。
直接输入数组的代码如下(loc[0,]即为输入数组的位置):

def fill_pe_data():
    pe_data = pd.DataFrame(columns=["a0", "a1", "a2", "a3", "a4"])
    pe_data.loc[0, ] = [0, 40, 41, 42, 43]
    pe_data.loc[1, ] = [1, 0.8, 0.6, 0.4, 0.2]
    return pe_data

Pe_data = fill_pe_data()
Pe_dict = form_position_pe_rules(Pe_data)  # input the name and value of the Interval Pe_Dict, output the dict
Pe_array = position_rules_array(Pe_dict)  # dict can't be sorted to fit "sell" condition, so extract an array
MARKET_DATA = scan_data(MARKET_DATA, TRADE_RULES, INITIAL_FUND, Pe_dict, Pe_array)
CAGR = pow(MARKET_DATA.iloc[-1][8] / INITIAL_FUND,
           1 / ((MARKET_DATA.iloc[-1][0] - MARKET_DATA.iloc[0][0]).days / 365.25)) - 1
print("The CAGR is: " + "{:%}".format(CAGR))
print(Pe_data)

得到如下结果(index[0]即为该数组):

The CAGR is: 11.542281%
  a0   a1   a2   a3   a4
0  0   40   41   42   43
1  1  0.8  0.6  0.4  0.2
The programme takes 2.1904969215393066 s.

Process finished with exit code 0

可以看出,在同样的数组[0, 40, 41, 42, 43]对应下,得到的最优解11.54%与穷举法下的11.87%并不一致。
尝试调整穷举法,将最外层循环直接调整到最接近最优解的情况(i=35),代码如下(loc[0,]即为输入数组的位置):

for i in range(35, 39, 1):  
    for j in range(1, 39 - i, 1):
        for k in range(1, 39 - i - j, 1):
            for p in range(1, 39 - i - j - k, 1):
                if 39 - i - j - k - p >= 0:
                    Market_data2 = MARKET_DATA
                    Pe_series = [0, 5 + i, 5 + i + j, 5 + i + j + k, 5 + i + j + k + p]  
                    Pe_data.loc[0, ] = Pe_series  # update interval boundaries
                    # input the name and value of the Interval Pe_Dict, output the dict:
                    Pe_dict = form_position_pe_rules(Pe_data)
                    # dict can't be sorted to fit "sell" condition, so extract an array:
                    Pe_array = position_rules_array(Pe_dict)
                    # trade and update functions are connected with scan_data() below
                    Market_data2 = scan_data(Market_data2, TRADE_RULES, INITIAL_FUND, Pe_dict, Pe_array)
                    # Compound Annual Growth Rate: (current_value/initial_value)^(1/years)-1
                    CAGR = pow(Market_data2.iloc[-1][8] / INITIAL_FUND,
                               1 / ((Market_data2.iloc[-1][0] - Market_data2.iloc[0][0]).days / 365.25)) - 1
                    if CAGR > BEST_CAGR:
                        BEST_CAGR = CAGR
                        Best_pe_data = Pe_data
                        Best_market_data = Market_data2
                else:
                    break

print("The CAGR is: " + "{:%}".format(BEST_CAGR))
print("The BEST POSITION_PE_RULE is: ")
print(Best_pe_data)

得到结果11.54%与直接输入数组的结果一致(index[0]即为该数组):

The CAGR is: 11.542281%
The BEST POSITION_PE_RULE is: 
    a0   a1   a2   a3   a4
0    0   40   41   42   43
1  1.0  0.8  0.6  0.4  0.2
The programme takes 2.5337982177734375 s.

Process finished with exit code 0

初步分析:
调用数组的相关函数并无问题,前期已经多次调试,这次直接输入数组和调整穷举循环之后得到一致结果也可以作证,但是为何在一开始穷举的时候出现不一致的结果?因为出现最优结果的同时也保存了输入数组,根据数组能够判断各层循环的对应值,而且不存在多种输入导致同样数组的可能性(5+i的值为40, i只可能为35,其他值同理)。
进一步检查最优结果的运算过程文档,似乎传入的并非最后打印出的那一数组,但是问题出在哪里仍不得而知。

环境:
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
PyCharm 2023.1 (Community Edition) Runtime version: 17.0.6+10-b829.5 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.

还请各位不吝赐教!

该问题已解决,就是第一个回复的解决方案,原来代码在最内层循环中反复写入loc[0, ]带来的错误,改为直接在最内层循环中新建Dataframe。同时记录该最优Dataframe的时候使用.copy()功能,即解决此问题。
虽然仍不知道原因,但是确实已经解决。发出来也供大家参考。
可是我现在找不到第一个回复了,晕……

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
根据你提供的代码和信息,我初步分析可能是以下原因导致穷举法产生的输出值和直接输入数组得到的结果不一致:

1、 穷举法的范围不够广

在你的代码中,穷举法的范围是从1到38,而你得到的最优结果是[0, 40, 41, 42, 43]。也就是说,穷举法的范围并没有包括最优结果,因此无法得到正确的输出值。你尝试将最外层循环调整到35,这样就能够包括最优结果,因此得到了正确的结果。

2、 代码逻辑错误

在你的代码中,有一些函数和变量没有提供,因此无法确定是否存在代码逻辑错误。例如,函数form_position_pe_rulesposition_rules_array的实现以及变量TRADE_RULESINITIAL_FUNDMARKET_DATA等的赋值情况都不清楚,这些可能会影响到程序的正确性。

建议你检查一下以上问题,如果问题仍然存在,可以提供更完整的代码和相关函数的实现,以便更好地帮助你解决问题。下面是修改后的完整代码,供你参考:

import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import time

# initialize the parameters
INITIAL_FUND = 1000000.0

TRADE_RULES = [
    {"name": "buy", "type": "interval", "value": [0, 1]},
    {"name": "sell", "type": "interval", "value": [0, 1]}
]

MARKET_DATA = pd.read_csv("market_data.csv")
MARKET_DATA["date"] = pd.to_datetime(MARKET_DATA["date"])
MARKET_DATA.set_index("date", inplace=True)

Pe_data = pd.DataFrame(columns=["a0", "a1", "a2", "a3", "a4"])

BEST_CAGR = 0.0
Best_pe_data = pd.DataFrame()
Best_market_data = pd.DataFrame()


def form_position_pe_rules(df):
    pe_dict = {}
    for i in range(1, df.shape[1]):
        name = "p" + str(i)
        pe_dict[name] = [df.iloc[0, i - 1], df.iloc[1, i - 1]]
    return pe_dict


def position_rules_array(pe_dict):
    pe_array = []
    for key in sorted(pe_dict):
        pe_array.append([key, pe_dict[key][0], pe_dict[key][1]])
    return np.array(pe_array)


def scan_data(market_data, trade_rules, initial_fund, pe_dict, pe_array):
    position = {}
    fund = initial_fund
    asset = 0.0
    for i in range(market_data.shape[0]):
        for rule in trade_rules:
            if rule["type"] == "interval":
                if pe_dict[rule["name"]][0] <= market_data.iloc[i][1] <= pe_dict[rule["name"]][1]:
                    position[rule["name"]] = True
                else:
                    position[rule["name"]] = False
        if position["buy"] and asset == 0.0:
            asset = fund / market_data.iloc[i][1]
            fund = 0.0
        elif position["sell"] and asset != 0.0:
            fund = asset * market_data.iloc[i][1]
            asset = 0.0
    if asset != 0.0:
        fund = asset * market_data.iloc[-1][1]
    return pd.DataFrame([[market_data.iloc[0][0], fund, market_data.iloc[-1][1], pe_array]], columns=["start_date", "end_fund", "end_price", "pe_array"])


start_time = time.time()

for i in range(1, 44, 1):
    for j in range(1, 44 - i, 1):
        for k in range(1, 44 - i - j, 1):
            for p in range(1, 44 - i - j - k, 1):
                if 44 - i - j - k - p >= 0:
                    Market_data2 = MARKET_DATA.copy()
                    Pe_series = [0, i, i + j, i + j + k, i + j + k + p]
                    Pe_data.loc[0, :] = Pe_series
                    Pe_dict = form_position_pe_rules(Pe_data)
                    Pe_array = position_rules_array(Pe_dict)
                    Market_data2 = scan_data(Market_data2, TRADE_RULES, INITIAL_FUND, Pe_dict, Pe_array)
                    CAGR = pow(Market_data2.iloc[-1][2] / INITIAL_FUND,
                               1 / ((Market_data2.iloc[-1][0] - Market_data2.iloc[0][0]).days / 365.25)) - 1
                    if CAGR > BEST_CAGR:
                        BEST_CAGR = CAGR
                        Best_pe_data = Pe_data.copy()
                        Best_market_data = Market_data2.copy()
                else:
                    break

end_time = time.time()

print("The best CAGR is: " + str(BEST_CAGR))
print("The best PE data is:")
print(Best_pe_data)
print("The corresponding market data is:")
print(Best_market_data)
print("Time used: " + str(end_time - start_time) + " seconds")

如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

引用chatGPT作答,问题分析:

在这个问题中,代码中的穷举法的方法是通过对5个变量进行四层循环来产生数组,并在每次循环中计算该数组对应的CAGR值,最终输出最优的CAGR值和对应的数组。但是,对于同一个输入数组,穷举法得到的最优CAGR值和直接输入数组得到的CAGR值不同。

问题原因:

穷举法得到的最优解可能不是全局最优解。穷举法中采用了遍历所有可能的解,但是由于采用了一定的步长进行遍历,所以有可能会遗漏一些全局最优解,导致结果与直接输入数组得到的结果不同。同时,穷举法中可能会存在一些误差,比如计算过程中的舍入误差等,也可能导致最优解与直接输入数组得到的结果不同。

解决方案:

为了解决这个问题,可以采用以下方法:

1.尝试采用其他的搜索算法来代替穷举法,比如遗传算法、模拟退火算法等,以寻求全局最优解。这些算法可以更加灵活地进行搜索,避免了穷举法中的一些缺点。

2.调整穷举法的步长,以尽可能地避免遗漏全局最优解。可以根据实际情况来调整步长,使其更加接近最优解。比如在此问题中,可以将穷举法的最外层循环直接调整到最接近最优解的情况。

3.通过调整代码中的参数或者优化代码结构等方法,尽可能地减少误差的产生。比如可以使用更高精度的数值类型来避免舍入误差的产生,或者优化代码结构以提高计算精度。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
穷举法的正确性是保证通过枚举可能的所有结果来找到最优解,但是这种方法在输入数据较多的情况下会非常耗费时间和资源,通常情况下采用启发式算法来解决这个问题。

由于代码没有完整的可复现的环境,我们无法确定代码具体存在的问题所在。但是,我们可以通过以下方法来调试问题:

  1. 确保最优数组是正确的。验证最优数组是正确的,可以使用不同的代码来重新计算最优数组,然后将结果合并和比较。

  2. 缩小问题的规模。减少循环次数,缩小问题规模,来查看代码是否存在问题。

  3. 调试代码。在循环体内加入打印语句,来观察每一次循环的结果,以便发现错误的源头。

  4. 采用编译器或调试工具。可以使用编译器和调试工具来跟踪和分析代码的执行过程,找出错误所在。

根据以上方法,可能的原因是代码在穷举的过程中某些循环变量没有正确传递或者变量赋值的过程中出现了错误。可以逐个检查循环变量和变量赋值语句,确保变量正确传递和赋值。

最后,如果确实找不到错误的原因,可以考虑参考其他同类问题的解决方法,或者请一名几年经验的程序员帮忙检查代码。
如果我的回答解决了您的问题,请采纳!

基于gpt
这种情况可能是因为穷举法存在局限性,而且该算法的复杂度非常高,特别是在搜索空间非常大时。在这种情况下,穷举法可能会忽略某些解决方案或者无法找到最优解,因为可能存在无法考虑到的情况。

在该问题中,穷举法是按照一定的步长(1)递增四个变量的值,并计算对应的CAGR。如果在某个阶段存在一个非常小的步长可能会使得结果变得不一致。此外,穷举法需要耗费大量的时间来搜索解决方案,尤其是当搜索空间非常大时,例如该问题的输入数组中的39个整数。

另一个原因可能是程序在计算CAGR时,存在舍入误差或者浮点数精度问题。在Python中,浮点数计算可能会导致精度问题,尤其是当计算涉及到大量小数位的时候。可能需要使用高精度库或者改进算法来减少这种问题的影响