代码之家  ›  专栏  ›  技术社区  ›  Wesley Larson

Python中实现蒙特卡罗马尔可夫链时的错误

  •  1
  • Wesley Larson  · 技术社区  · 10 年前

    我试图在Python 2.7中使用numpy实现一个简单的Markov Chain Monte Carlo。我们的目标是找到“背包问题”的解决方案,即给定一组m个价值vi和重量wi的物品,以及一个容量为b的袋子,您可以找到可以放入袋子中的物品的最大价值,以及这些物品是什么。我是在夏天开始编码的,我的知识非常不平衡,所以如果我错过了一些明显的东西,我很抱歉,我是自学成才的,一直在到处跳。

    该系统的代码如下(我将其拆分为多个部分,试图找出问题所在)。

    import numpy as np
    import random
    
    
    def flip_z(sackcontents): 
        ##This picks a random object, and changes whether it's been selected or not.
        pick=random.randint(0,len(sackcontents)-1)
        clone_z=sackcontents
        np.put(clone_z,pick,1-clone_z[pick])
        return clone_z
    
    def checkcompliance(checkedz,checkedweights,checkedsack):
        ##This checks to see whether a given configuration is overweight
        weightVector=np.dot(checkedz,checkedweights)
        weightSum=np.sum(weightVector)
        if (weightSum > checkedsack):
            return False
        else:
            return True
    
    def getrandomz(length):
        ##I use this to get a random starting configuration.
        ##It's not really important, but it does remove the burden of choice.       
        z=np.array([])
        for i in xrange(length):
            if random.random() > 0.5:
                z=np.append(z,1)
            else:
                z=np.append(z,0)
        return z
    
    def checkvalue(checkedz,checkedvalue):
        ##This checks how valuable a given configuration is.
        wealthVector= np.dot(checkedz,checkedvalue)
        wealthsum= np.sum(wealthVector)
        return wealthsum
    
    def McKnapsack(weights, values, iterations,sack): 
        z_start=getrandomz(len(weights))
        z=z_start
        moneyrecord=0.
        zrecord=np.array(["error if you see me"])
        failures=0.
        for x in xrange(iterations):
            current_z= np.array ([])
            current_z=flip_z(z)
            current_clone=current_z
            if (checkcompliance(current_clone,weights,sack))==True:
                z=current_clone
                if checkvalue(current_z,values)>moneyrecord:
                    moneyrecord=checkvalue(current_clone,values)
                    zrecord= current_clone
            else:failures+=1
        print "The winning knapsack configuration is %s" %(zrecord)
        print "The highest value of objects contained is %s" %(moneyrecord)
    
    testvalues1=np.array([3,8,6])
    testweights1= np.array([1,2,1])
    
    McKnapsack(testweights1,testvalues1,60,2.)
    

    应该发生的情况如下:当最大承载能力为2时,它应该在不同的潜在行李承载配置之间随机切换,其中有2^3=8个测试重量和我给它的值,z中的每一个1或0表示有或没有给定的物品。它应该丢弃权重过大的选项,同时跟踪具有最高值和可接受权重的选项。正确的答案是将1,0,1视为配置,将9视为最大值。当我每次使用适度高的迭代次数时,我都会得到9个值,但配置似乎完全随机,并且在某种程度上打破了权重规则。我已经用很多测试数组再次检查了我的“checkcompliance”函数,并且它似乎有效。这些错误的、超重的配置是如何通过我的if语句进入我的zrecord的?

    1 回复  |  直到 10 年前
        1
  •  2
  •   Jeff G    10 年前

    诀窍是 z (因此 current_z 而且 zrecord )最终总是引用内存中完全相同的对象。 flip_z 通过 np.put .

    一旦你找到了一种新的组合 moneyrecord ,您设置了一个对它的引用,但在随后的迭代中,您继续在同一引用处更改数据。

    换句话说,像

    current_clone=current_z
    zrecord= current_clone
    

    不要 复制 ,它们只对内存中的相同数据进行另一个别名。

    解决此问题的一种方法是,一旦您发现该组合是赢家,就显式复制该组合:

    if checkvalue(current_z, values) > moneyrecord:
        moneyrecord = checkvalue(current_clone, values)
        zrecord = current_clone.copy()