我正在尝试(再次: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点)。 我听说“删除”很慢。我将如何优化此代码?
答案 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的加速。基本上,没有类型检查每次迭代的开销,您的循环将运行得更快。它几乎就像有矢量化,虽然它们不一样。