【问题标题】:Python methods to reduce running times KTNS algorithm减少运行时间的 Python 方法 KTNS 算法
【发布时间】:2018-10-11 16:44:45
【问题描述】:

我一直在尝试开发一种算法,称为尽快保持所需工具,但在模拟过程中,我意识到运行时间太长。

我想减少运行时间并检查其他关于如何快速 python 编码的问题Is Python slower than Java/C#? [closed] 我找到了几个解决方案,但我不知道如何在我的代码中实现它们。

在我的电脑上它需要 0.004999876022338867 秒,但主要问题是对于整个程序,这个函数被调用了 13,000 次。

这里附上我的全部代码,如果您有任何改进建议,请随时与我分享。

import sets
import numpy
import copy
import time

J= {1: [6, 7],2: [2, 3], 3: [1, 6, 9], 4: [1, 5, 9], 5: [5, 8, 10], 6: [1, 3, 6, 8], 7: [5, 6, 8, 9], 8: [5, 7, 8], 9: [1, 4, 5, 8], 10: [1, 2, 4, 10]}

def KTNS(sigma=[10, 9, 4, 1, 6, 3, 7, 5, 2, 8], Jobs=J,  m=10 ,capacity=4 ):
    t0=time.time()
    Tools = {}
    Lin={}
    n=len(sigma) 
    for i in range(1,m+1): 
        for e in sigma: 
            if i in Jobs[e]:
                Tools[i]=sets.Set([])

    count = 1
    available_tools=sets.Set()
    for e in sigma:
        for i in Jobs[e]:
            Tools[i].add(count)
            available_tools.add(i)
        count+=1
    Tin=copy.deepcopy(Tools)
    for e in Tin:
        Lin[e]=min(Tin[e])
    count=1
    J = numpy.array([0] *m)
    W = numpy.array([[0] * m] * n)
    while count<=len(sigma):
        for e in Tools:
            if len(available_tools)<capacity:
                reference=len(available_tools)
            else:
                reference=capacity
            while numpy.count_nonzero(J == 1) <reference: 
                min_value = min(Lin.itervalues())
                min_keys = [k for k in Lin if Lin[k] == min_value]
                temp = min_keys[0] #min(Lin, key=Lin.get)
                if min_value>count:
                    if len(min_keys)>=2:
                        if count==1:
                            J[temp - 1] = 1
                            Lin[temp] = '-'
                        else:
                            J0=W[count-2]
                            k=0
                            for elements in min_keys: #tested
                                if numpy.count_nonzero(J == 1) < reference:
                                    if J0[elements-1]==1:
                                        J[elements-1]=1
                                        Lin[elements]='-'
                                        k=1
                                    else:
                                        pass
                                else:
                                    pass
                            if k==0: 
                                J[temp - 1] = 1
                                Lin[temp] = '-'
                    else: 
                        J[temp - 1] = 1
                        Lin[temp] = '-'
                else:
                    J[temp-1]=1
                    Lin[temp] = '-'
            Tin[e].discard(count)
            for element in Tin:
                try:
                    Lin[element] = min(Tin[element])
                except ValueError:
                    Tin[element]=sets.Set([len(sigma)+1])
                    Lin[element]=len(sigma)+1
        W[count-1]=J
        J= numpy.array([0] *m)
        count+=1
    Cost=0
    for e in range(1,len(sigma)):
        temp=W[e]-W[e-1]
        temp[temp < 0] = 0
        Cost+=sum(temp)

    return Cost+capacity,time.time()-t0

【问题讨论】:

  • 您是否真的希望有人检查您的代码,弄清楚它的作用并提出改进建议?
  • 如果您想要对工作代码进行完整的代码审查,请尝试codereview.stackexchange.com - 但在发布之前请阅读帮助中心,以确保您的问题与主题相关!
  • 详细解释您正在实施的算法也会有所帮助。
  • 将时间乘以 13,000,我得到整个过程需要 65 秒。它应该花费的最长时间是多少?我确实同意 Blorgbeard 的观点——虽然很多人被错误地告知去 codereview,但你已经有了希望人们查看的功能齐全的代码。这个问题很适合那里,只要确保你提到它是在这里交叉发布的。 (这里不是离题,但在那里可能会更受欢迎,所以我不会投票结束。)
  • 您应该为变量使用更好的命名约定,并且可能将此函数分解为许多较小的函数。实际上,要弄清楚这段代码的作用需要一段时间。

标签: python algorithm performance time


【解决方案1】:

一个建议 - 尽量减少对字典的使用。看起来您的许多字典都可以是列表。字典访问比python中的列表访问慢很多。

看起来您可以简单地将 Tools、Lin 和 Tin 都设为列表,例如Lin = [] 而不是 Lin = {},我希望您会看到性能的显着提升。

您知道 3 个字典的大小,因此只需将它们初始化为您需要的大小。创建Lin和Tools如下:

Lin = [None] * m+1
Tools = [None] * m+1
Tin = [None] * m+1

这将创建一个 m+1 个元素的列表(这是从 1 到 m+1 的循环所得到的)。由于您正在执行基于 1 的索引,因此它会在 Lin[0]、Tools[0] 等中留下一个空白位置,但您将能够访问 Lin[1] - Lin[10],就像您一样目前正在做。 您可以自己尝试的简单示例:

python3 -m timeit -s 'foo = [x for x in range(10000)]' 'foo[500]'

100000000 次循环,3 次取胜:每个循环 0.0164 微秒

python3 -m timeit -s 'foo = {x: x for x in range(10000)}' 'foo[500]'

10000000 次循环,3 次中的最佳:每个循环 0.0254 微秒

只需将您的字典更改为列表,您就可以获得几乎 2 倍的改进。您的 65 秒任务现在大约需要 35 秒。

顺便说一句,请查看tips on improving speed 的 python wiki,其中包含许多关于如何分析您的函数的参考。

【讨论】:

  • 我怎样才能使字典的使用适应列表?目前,我正在使用字典,因为它们很容易访问和更新信息。如果我使用列表并删除一些元素,则索引将被修改,我不会知道。有什么想法吗?
  • 请记住,列表也是动态的,您可以将push 附加到索引、附加到末尾和del 特定索引,尽管我在您的代码中看不到任何地方需要那个。你永远不会添加到 Lin、Tin 或 Tools,尽管你确实添加到了你放在 Tools[i] 中的集合。只需创建您的列表。我在答案中做了一个小调整,以使其更清楚。祝你好运!
猜你喜欢
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
  • 2019-04-21
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多