ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python-优化排列搜索循环(不能使用itertools),速度非常慢.有什么建议么?

2019-11-11 04:57:14  阅读:287  来源: 互联网

标签:optimization itertools permutation pypy python


这是一个游戏,您有12张牌,然后选择您,直到从同一组中选择3张.我试图找到选择每个小组的可能性.我创建的脚本可以运行,但是速度非常慢.我的同事在R中创建了类似的脚本,但没有这些函数,而他的脚本所花费的时间是我的脚本的1/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

“最大选择数”代表不同“卡”的总数.总选择数代表用户选择的最大数量.这是因为经过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')

解决方法:

好的,这次我希望我能解决您的问题:)

为了从算法上加快程序速度,需要两个洞察力(我想您是出于完整性的考虑而拥有它们):

>序列(card_1,card_2)和(card_2,card_1)的概率不相等,因此我们无法使用urn问题的结果,看来我们需要尝试所有排列.
>但是,考虑到到目前为止我们选择的一组纸牌,我们实际上并不需要这些信息以什么顺序选择它们-在以后的游戏中都是一样的.因此,使用动态编程并计算游戏期间要遍历的每个子集的概率就足够了(因此,我们需要检查2 ^ N而不是N!个状态).

对于一组拾取的卡,设置下一轮拾取i的概率为:

 norm:=sum Wi for i in set 
 P(i|set)=Wi/norm if i not in set else 0.0

计算P(set)的递归-游戏期间出现一组被选牌的概率为:

set_without_i:=set/{i}
P(set)=sum P(set_without_i)*P(i|set_without_i) for i in set

但是,仅应针对尚未结束游戏的set_without_i进行此操作,即,没有小组选择3张牌.

这可以通过递归记忆或通过使用自下而上的动态编程来实现.它还使用整数的二进制表示形式表示集合,并且(最重要的部分!)几乎立即返回结果[(‘Grand’,0.0014104762718021384),(‘Major’,0.0028878988709489244),(‘Minor’,0.15321793072867956),(‘奖金”,0.84248369412856905)]:

#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)

对代码中使用的“技巧”的一些解释:

一个非常标准的技巧是使用整数的二进制表示形式对集合进行编码.假设我们有对象[a,b,c],因此我们可以将集合{b,c}表示为110,这意味着a(列表中的第一个对应于0-最低数字)-不在集合中,集合中的b(1),集合中的c(1).但是,将110读为整数则是6.

current_set-for循环可模拟游戏,并在玩游戏时能更好地理解.让我们玩两张权重为[2,1]的卡片[a,b].

我们从一个空集开始游戏,0为整数,因此概率向量(给定集,其二进制表示形式以及作为映射到概率的整数):

  probs=[{}=00=0->1.0,  01={a}=1->0.0, {b}=10=2->0.0, {a,b}=11=3->0.0]

我们处理current_set = 0,有两种可能性分别是66%拿卡a和33%拿卡card,因此概率在处理后变为:

 probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->0.0]

现在我们处理current_set = 1 = {a},唯一的可能就是取b,所以我们将以集合{a,b}结尾.因此,我们需要通过公式更新其(3 = {a,b})概率,然后得出:

 probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->0.66]

在下一步中,我们处理2,给定集合{b}的唯一可能性是选择卡片a,因此需要再次更新集合{a,b}的概率

probs=[{}=00=0->1.0,  01={a}=1->0.66, {b}=10=2->0.33, {a,b}=11=3->1.0]

我们可以在两条不同的路径上到达{a,b}-这可以在我们的算法中看到.在我们游戏的某个时刻经过集合{a,b}的概率显然为1.0.

另一重要的事情是:在处理此集合之前,将处理所有通往{a,b}的路径(这将是下一步).

标签:optimization,itertools,permutation,pypy,python
来源: https://codeday.me/bug/20191111/2017399.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有