Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 优化极慢的置换搜索循环(不能使用itertools)。有什么建议吗?_Python_Optimization_Permutation_Itertools_Pypy - Fatal编程技术网

Python 优化极慢的置换搜索循环(不能使用itertools)。有什么建议吗?

Python 优化极慢的置换搜索循环(不能使用itertools)。有什么建议吗?,python,optimization,permutation,itertools,pypy,Python,Optimization,Permutation,Itertools,Pypy,这是一个游戏,你有12张牌,你选择你,直到你从同一组中选择3张。我试图找出选择每组的概率。我创建的脚本可以工作,但速度非常慢。我的同事在R中创建了一个类似的脚本,没有函数,他的脚本花费的时间是我的脚本的100分之一。我只是想弄清楚原因。任何想法都将不胜感激 from collections import Counter import pandas as pd from datetime import datetime weight = pd.read_excel('V01Weights.xls

这是一个游戏,你有12张牌,你选择你,直到你从同一组中选择3张。我试图找出选择每组的概率。我创建的脚本可以工作,但速度非常慢。我的同事在R中创建了一个类似的脚本,没有函数,他的脚本花费的时间是我的脚本的100分之一。我只是想弄清楚原因。任何想法都将不胜感激

from collections import Counter
import pandas as pd
from datetime import datetime

weight = pd.read_excel('V01Weights.xlsx')
重量如下所示:

Symb    Weight
Grand   170000
Grand   170000
Grand   105
Major   170000
Major   170000
Major   215
Minor   150000
Minor   150000
Minor   12000
Bonus   105000
Bonus   105000
Bonus   105000
Max Picks表示不同“卡”的总数。Total Picks表示用户选择的最大数量。这是因为在8次选择之后,你保证每种类型有2次,所以在第9次选择时,你保证有3次匹配

TotalPicks = 9
MaxPicks = 12
这应该被命名为PickedProbabilities

Picks = {0:0,1:0,2:0,3:0}
这是我的timeit类的简单版本,因为我不喜欢timeit类

def Time_It(function):
    start =datetime.now()

    x = function()

    finish = datetime.now()

    TotalTime = finish - start

    Minutes = int(TotalTime.seconds/60)
    Seconds = TotalTime.seconds % 60


    print('It took ' + str(Minutes) + ' minutes and ' + str(Seconds) + ' seconds')

    return(x)
给定x(我的选择顺序),我找到概率。这些镐没有更换

def Get_Prob(x,weight):
    prob = 1
    weights = weight.iloc[:,1]

    for index in x:
        num = weights[index]
        denom = sum(weights)

        prob *= num/denom
        weights.drop(index, inplace = True)
        # print(weights)

    return(prob)
这用于确定我的循环中是否存在重复项,因为这是不允许的

def Is_Allowed(x):
    return(len(x) == len(set(x)))
这决定了目前为止所有的牌中是否都有赢牌

def Is_Win(x):
    global Picks

    WinTypes = [[0,1,2],[3,4,5],[6,7,8],[9,10,11]]

    IsWin = False

    for index,item in enumerate(WinTypes):
        # print(index)
        if set(item).issubset(set(x)):
            IsWin = True
            Picks[index] += Get_Prob(x,weight)
            # print(Picks[index])
            print(sum(Picks.values()))
            break

    return(IsWin)
这是我的主要功能,可以循环使用所有卡。我试图使用递归来实现这一点,但最终还是放弃了。我无法使用itertools创建所有置换,因为例如[0,1,2,3,4]将由itertools创建,但这是不可能的,因为一旦获得3个匹配,游戏结束

def Cycle():

    for a in range(MaxPicks):
        x = [a]

        for b in range(MaxPicks):
            x = [a,b]

            if Is_Allowed(x):
                for c in range(MaxPicks):
                    x = [a,b,c]
                    if Is_Allowed(x):                    
                        if Is_Win(x):
                            # print(x)
                            continue
                        for d in range(MaxPicks):
                            x = [a,b,c,d]
                            if Is_Allowed(x):
                                if Is_Win(x):
                                    # print(x)
                                    continue
                            for e in range(MaxPicks):
                                x = [a,b,c,d,e]
                                if Is_Allowed(x):
                                    if Is_Win(x):
                                        continue
                                for f in range(MaxPicks):
                                    x = [a,b,c,d,e,f]
                                    if Is_Allowed(x):
                                        if Is_Win(x):
                                            continue
                                    for g in range(MaxPicks):
                                        x = [a,b,c,d,e,f,g]
                                        if Is_Allowed(x):
                                            if Is_Win(x):
                                                continue
                                        for h in range(MaxPicks):
                                            x = [a,b,c,d,e,f,g,h]
                                            if Is_Allowed(x):
                                                if Is_Win(x):
                                                    continue
                                            for i in range(MaxPicks):
                                                if Is_Allowed(x):
                                                    if Is_Win(x):
                                                        continue
调用主函数

x = Time_It(Cycle)
print(x)
将概率写入文本文件

with open('result.txt','w') as file:
    # file.write(pickle.dumps(x))
    for item in x:
        file.write(str(item) + ',' + str(x[item]) + '\n')
我的同事在R中创建了一个类似的脚本,没有函数,他的脚本花费的时间是我的脚本的100分之一

两个简单的优化:

1) 实际上,像
这样的函数调用是允许的()
,因为Python有很多函数调用开销(例如创建新的stackframe和参数元组)


2) 在中运行代码,该代码非常擅长优化像这样的函数。

编辑:我误解了原始问题,这里提供的解决方案针对以下问题:

给4组3张不同的牌,每张牌的分数不同,只要我们没有从同一组中选3张牌,我们就选牌。游戏结束时的预期分数(所选牌的分数之和)是多少

我不考虑这个问题的解决方案,因为经过这么多年的概率论研究,我很高兴能解决这个问题,我就是不能删除它:)

有关原始问题的处理,请参见我的其他答案


提高性能有两种可能:使代码更快(在开始之前,应该分析程序的哪些部分应该优化,否则时间就花在优化不重要的事情上)或改进算法。我提议做第二件事

好的,这个问题似乎比第一个站点更复杂。让我们从一些观察开始


您需要知道的是游戏结束时所选牌的预期数量:

import math

def binom(n,k):
  return math.factorial(n)//math.factorial(k)//math.factorial(n-k)

#expected number of cards:

n=12 #there are 12 cards
probs=[0]*n
for minor in xrange(3):
  for major in xrange(3):
     for bonus in xrange(3):
         i = 3 + minor +major +bonus 
         P_urn = binom(3,2)*binom(3,minor)*binom(3,major)*binom(3,bonus)/float(binom(n, n-i+1))
         P_right_last_card = 1.0/(n-i+1)
         probs[i]+=4*P_urn*P_right_last_card #factor 4 from symmetry


print "Expected number of cards:", sum((prob*card_cnt for card_cnt, prob in enumerate(probs)))
如果
Pi
是在游戏过程中某个地方拾取卡
i
的概率,那么我们将寻找得分
E(得分)=P1*W1+P2*W2+…Pn*Wn
的预期值。然而,如果我们看一组的卡片,我们可以说明,由于对称性,该组卡片的概率是相同的,例如,在您的案例中,
P1=P2=P3=:Pgrand
。因此,可以计算出我们的期望值:

E(Score)=3*Pgrand*(W1+W2+W3)/3+...+3*Pbonus*(W10+W11+W12)/3
我们称之为
averageWgrand:=(W1+W2+W3)/3
,并注意到
E(#grand)=3*Pgrand
——游戏结束时挑选的大牌的预期数量。由此,我们的公式变成:

E(Score)=E(#grand)*averageWgrand+...+E(#bonus)*averageWbonus
在你的例子中,我们可以更进一步:每组的牌数相等,因此由于对称性,我们可以声称:
E(#grand)=E(#minor)=E(#major)=E(#grand)=:(E#group)
。为了简单起见,在下面我们只考虑这种特殊情况(但概略的解决方案也可以扩展到一般情况)。这导致以下简化:

E(Score)=4*E(#group)(averageWgrand+...+averageWbonus)/4
我们将
averageW:=(averageWgrand+…+averageWbonus)/4
称为
E(#卡片)=4*E(#grand)
是游戏结束时所选卡片的预期数量

因此,
E(Score)=E(#卡片)*averageW
,因此我们的任务简化为在游戏结束时计算卡片数量的预期值:

 E(#cards)=P(1)*1+P(2)*2+...P(n)*n
其中
p(i)
表示游戏以确切的
i
牌结束的概率。概率
P(1)
P(2)
P(k)
k>9
很容易看到-它们是
0


计算以
i
拾取的卡结束游戏的概率-
p(i)

import math

def binom(n,k):
  return math.factorial(n)//math.factorial(k)//math.factorial(n-k)

#expected number of cards:

n=12 #there are 12 cards
probs=[0]*n
for minor in xrange(3):
  for major in xrange(3):
     for bonus in xrange(3):
         i = 3 + minor +major +bonus 
         P_urn = binom(3,2)*binom(3,minor)*binom(3,major)*binom(3,bonus)/float(binom(n, n-i+1))
         P_right_last_card = 1.0/(n-i+1)
         probs[i]+=4*P_urn*P_right_last_card #factor 4 from symmetry


print "Expected number of cards:", sum((prob*card_cnt for card_cnt, prob in enumerate(probs)))
让我们玩一个稍有不同的游戏:我们准确地选择
i
牌,并在以下情况下获胜:

  • 只有一组被挑选了3张牌。我们称这个组为
    full\u组
  • 最后挑选的(第i张)卡片来自
    full\u组
  • 很容易看出,赢得这场比赛的概率正是我们所寻找的概率-
    p(i)
    。再一次,我们可以使用对称性,因为所有的群都是相等的(
    P(win,full=grand)
    表示我们所做的和
    full\u群=grand
    )的概率:

    p(赢,大)
    是以下概率:

  • 拾取
    i-1
    卡后,拾取的大卡数为2,即“grand=2”和
  • 拾取
    i-1
    卡后,每组拾取的卡数少于3张,并且
  • 我们在最后一轮中选了一张大牌。假设前两个约束成立,该(条件)概率为
    1/(n)-
    
    P(win, grand) = 1/(n-i+1)*sum P(#grand=2, #minor=x, #major=y, #bonus=z)
                   where x<=2, y<=2, z<=2 and 2+x+y+z=i-1
    
    import math
    
    def binom(n,k):
      return math.factorial(n)//math.factorial(k)//math.factorial(n-k)
    
    #expected number of cards:
    
    n=12 #there are 12 cards
    probs=[0]*n
    for minor in xrange(3):
      for major in xrange(3):
         for bonus in xrange(3):
             i = 3 + minor +major +bonus 
             P_urn = binom(3,2)*binom(3,minor)*binom(3,major)*binom(3,bonus)/float(binom(n, n-i+1))
             P_right_last_card = 1.0/(n-i+1)
             probs[i]+=4*P_urn*P_right_last_card #factor 4 from symmetry
    
    
    print "Expected number of cards:", sum((prob*card_cnt for card_cnt, prob in enumerate(probs)))
    
     norm:=sum Wi for i in set 
     P(i|set)=Wi/norm if i not in set else 0.0
    
    set_without_i:=set/{i}
    P(set)=sum P(set_without_i)*P(i|set_without_i) for i in set
    
    #calculates probability to end the game with 3 cards of a type
    
    
    N=12
    
    #set representation int->list
    def decode_set(encoded):
        decoded=[False]*N
        for i in xrange(N):
            if encoded&(1<<i):
                decoded[i]=True
        return decoded
    
    weights = [170000, 170000, 105, 170000, 170000, 215, 150000, 150000, 12000, 105000, 105000, 105000]     
    def get_probs(decoded_set):
        denom=float(sum((w for w,is_taken in zip(weights, decoded_set) if not is_taken)))
        return [w/denom if not is_taken else 0.0 for w,is_taken in zip(weights, decoded_set)]
    
    def end_group(encoded_set):
        for i in xrange(4):
           whole_group =  7<<(3*i) #7=..000111, 56=00111000 and so on
           if (encoded_set & whole_group)==whole_group:
               return i
        return None
    
    
    #MAIN: dynamic program:
    
    MAX=(1<<N)#max possible set is 1<<N-1
    probs=[0.0]*MAX
    
    #we always start with the empty set:
    probs[0]=1.0    
    #building bottom-up
    for current_set in xrange(MAX):
        if end_group(current_set) is None:  #game not ended yet!
           decoded_set=decode_set(current_set)
           trans_probs=get_probs(decoded_set)
           for i, is_set in enumerate(decoded_set):
               if not is_set:
                  new_set=current_set | (1<<i) 
                  probs[new_set]+=probs[current_set]*trans_probs[i]
    
    #filtering wins:
    group_probs=[0.0]*4
    for current_set in xrange(MAX):
       group_won=end_group(current_set)
       if group_won is not None:
          group_probs[group_won]+=probs[current_set]
    
    
    print zip(["Grand", "Major", "Minor", "Bonus"], group_probs)
    
      probs=[{}=00=0->1.0,  01={a}=1->0.0, {b}=10=2->0.0, {a,b}=11=3->0.0]
    
     probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->0.0]
    
     probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->0.66]
    
    probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->1.0]