Pythonic方式存储前10名结果
我正在研究一个
python项目,该项目在完成所有计算之前运行了几个小时.我希望随着计算的进展保持前10项计算结果.
有明显的做法: if calc > highest_calc: second_calc = highest_calc highest_calc = calc if calc < highest_calc and calc > second_calc: third_calc = second_calc second_calc = calc if calc < second_calc and calc > third_calc: fourth_calc = third_calc third_calc = calc etc. 但是,有更好,更有活力和更pythonic的方式吗? 奖金 对于我的项目,每个calcultion都有三个相应的名称:name_a name_b name_c.我不想要的是拥有相同三个名字的前10个值中的一个.但是,如果最后一个计算具有相同的名称,我想保持两者中最高的.最好的方法是什么? 例如,假设2.3是calc的值,使用MCD SBUX和CAT来计算calc.但是,如果我已经使用MCD SBUX和CAT进行了一次计算并且它已经达到了顶峰呢?如何找到此计算的值,以便我可以看到它是否小于或大于新计算结果.如果它大于,则删除旧的calc并添加新的calc.如果小于,则传递新的计算结果.希望这是有道理的: If name_a in top10 and name_b in top10 and name_c in top10: if calc > old_calc_with_same_names: add_calc = calc,name_a,name_b,name_c top10.insert(bisect.bisect(calc,top10[0]),add_calc) else: add to top10 完成的代码 csc = [] top_ports = [] add_sharpe = [sharpe,weight_a,exchange_a,weight_b,exchange_b,name_c,weight_c,exchange_c] if init__calc == 0: csc.append(add_sharpe) if init__calc > 1: if name_a == prev_name_a and name_b == prev_name_b and name_c == prev_name_c: csc.append(add_sharpe) if name_a != prev_name_a or name_b != prev_name_b or name_c != prev_name_c: if csc: hs = max(csc,key=lambda x: x[0]) if top_ports: ls = min(top_ports,key=lambda x: x[0]) if hs[0] > ls[0]: hsi = csc.index(hs) top_ports.append(csc[hsi]) else: hsi = csc.index(hs) top_ports.append(csc[hsi]) csc = [] csc.append(add_sharpe) 后来在剧本中…… top_ports = sorted(top_ports,key=itemgetter(0),reverse=True) print "The highest sharpe is: {0}".format(top_ports[0]) print " ===============================================" print " ===============================================" print datetime.now() - startTime print "Second: {0}".format(top_ports[1]) print "Third: {0}".format(top_ports[2]) print "Fourth: {0}".format(top_ports[3]) print "Fifth: {0}".format(top_ports[4]) 等等 解决方法
使用heapq模块.它不是不必要地存储所有结果,而是在每一步添加新结果然后有效地移除最低 – 可能是刚添加的那个 – 有效地保持前10名.存储所有结果不一定是坏的;收集统计数据可能很有价值,并且可以更容易地确定之后要保留的内容.
from heapq import heappush,heappushpop heap = [] for x in [18,85,36,57,2,45,55,1,28,73,95,38,89,15,7,61]: calculation_result = x + 1 # Dummy calculation if len(heap) < 10: heappush(heap,calculation_result) else: heappushpop(heap,calculation_result) top10 = sorted(heap,reverse=True) # [96,90,86,74,62,58,56,46,39,37] 请注意,此模块具有更多有用的功能,仅请求最高/最低值等.这可以帮助您添加有关名称的行为. 实际上这个构造很常见,因为它可以作为heapq.nlargest使用.但是,为了不存储所有结果,您必须将计算器建模为生成器,这有点高级. from heapq import nlargest def calculate_gen(): for x in [18,61]: yield x + 1 # Dummy calculation top10 = nlargest(10,calculate_gen()) # [96,37] 奖金 以下是对每个关联名称组合使结果唯一的一些想法. 使用堆不会再削减它了,因为堆不能很好地定位任何不是绝对最小值/最大值的项,而我们感兴趣的是给定名称组合标准的某种局部最小值. 相反,您可以使用dict为每个名称组合保留最高值.首先,您需要将名称组合编码为不可变值,以使其作为键使用,并且因为名称的顺序无关紧要,所以决定一些顺序并坚持下去.我将使用字母字符串来保持简单. 在下面的代码中,每个结果都放在dict中一个对于其名称组合唯一的位置 – 因此可能需要标准化 – 只要没有更好的结果.后来,前n个是根据每个组合的最高结果编译的. from heapq import nlargest calculations = [('ABC',18),('CDE',85),('BAC',36),57),('ECD',2),('BAD',45),('EFG',55),('DCE',1)] highest_per_name_combi = dict() for name_combi,value in calculations: normal_name_combi = ''.join(sorted(name_combi)) # Slow solution current = highest_per_name_combi.get(normal_name_combi,float('-inf')) highest_per_name_combi[normal_name_combi] = max(value,current) top3 = nlargest(3,highest_per_name_combi.iteritems(),key=lambda x: x[1]) 这种方法的唯一问题可能是使用的内存量.由于有150个名字可以有551300(150选3)组合,你可能不得不决定不时地清理字典,这很简单.在循环中,检查dict的大小,如果它超过某个(仍然很大)数字,则组成当前的前n个并从中创建一个新的最小dict.此外,可以通过减少查找/调用的数量来应用一些微优化,例如,不使用get和/或max. 如果您可以控制执行计算的顺序,那么所有这些都会容易得多.如果您知道接下来的1000个计算都是针对相同的名称组合,那么在将其添加到整体结果之前,您可以先找到最好的计算. 此外,真正大量的结果,最简单的方法实际上可能是最好的.只需将它们以方便的格式写入文件,然后对它们进行排序(首先按名称组合,然后按值反向排序),只对每个名称组合进行第一次出现(分组时很容易)并再次对结果进行排序,只需按值. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |