在Python中优化Pareto前端过滤

时间:2015-12-01 07:24:36

标签: python

我正在尝试(再次:Fast calculation of Pareto front in Python)过滤列表列表,只保留非支配集。

我整理了一个最终适合我的脚本:

import operator
import copy
import time
import random

def select_dominated(a,b):
    ge = all(map(operator.ge, a, b))
    le = all(map(operator.le, a, b))
    # return dominated
    return b if ge else a if le else 'indifferent'

def paretoFront(a):
    b = copy.deepcopy(a)
    if len(a) > 1:
        for i in range(len(a)):
            for j in range(i,len(a)):
                if i != j:
                    try:
                        b.remove(select_dominated(a[i],a[j]))
                    except:
                        ""
    return b

set = []
for i in range(1000):
    set.append([random.random(),random.random(),random.random()])

t0 = time.time()
print len(set),"->",len(paretoFront(set)),"in",time.time()-t0,"seconds"

期待,对于大型列表,它非常慢(3秒,过滤1000个3d点)。 我听说“删除”很慢。我将如何优化此代码?

1 个答案:

答案 0 :(得分:1)

(免责声明:我并不精通Pareto前端,所以我根据你提供的内容推断代码是什么。)

因为这是纯Python(即没有使用外部库),所以大部分时间都花在迭代上(你的for循环)。

我建议采用两种策略。

首先,看看你的代码是否可以矢量化。例如,您可能希望将数据表示为numpy数组。无耻地从here复制代码,您可能想要这样做:

def pareto_frontier_multi(myArray):
    # Sort on first dimension
    myArray = myArray[myArray[:,0].argsort()]
    # Add first row to pareto_frontier
    pareto_frontier = myArray[0:1,:]
    # Test next row against the last row in pareto_frontier
    for row in myArray[1:,:]:
        if sum([row[x] >= pareto_frontier[-1][x]
                for x in range(len(row))]) == len(row):
            # If it is better on all features add the row to pareto_frontier
            pareto_frontier = np.concatenate((pareto_frontier, [row]))
    return pareto_frontier

my_array = np.random.random((3, 1000))
pareto_frontier_multi(my_array)

numpy使用矢量化来提高速度。

其次,如果你想坚持使用纯Python,那么你可以试试PyPy。下载PyPy可执行文件二进制文件,让你的bash终端识别它们所在的位置(通过编辑bash shell PATH变量),然后在PyPy下执行你的代码。我写了一个blog post,可以告诉你PyPy的加速。基本上,没有类型检查每次迭代的开销,您的循环将运行得更快。它几乎就像有矢量化,虽然它们不一样。