我正在研究一个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.
Run Code Online (Sandbox Code Playgroud)
但是,有更好,更有活力和更pythonic的方式吗?
奖金
对于我的项目,每个计算都有三个相应的名称:name_a name_b name_c.我不想要的是拥有相同三个名字的前10个值中的一个.但是,如果最后一个calc具有相同的名称,我想保持两者中最高的一个.最好的方法是什么?
例如,假设2.3是calc,使用MCD SBUX和CAT计算的值calc.但是,如果我已经做了一个calc使用MCD SBUX和CAT它做了它对顶?我如何找到它的值,calc以便我可以看到它是否小于或大于新的值calc.如果大于,则删除旧的calc并添加新的calc calc.如果它小于,则pass新计算.希望这是有道理的:
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
Run Code Online (Sandbox Code Playgroud)
完成的代码
csc = []
top_ports = []
add_sharpe = [sharpe, name_a, weight_a, exchange_a, name_b, 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)
Run Code Online (Sandbox Code Playgroud)
后来在剧本中......
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])
Run Code Online (Sandbox Code Playgroud)
等等
Pau*_*ney 11
最简单的方法是将所有分数存储在一个列表中,然后将其排序(最高的第一个)并获取前10个.
import random
# sample random scores
scores = [int(1000*random.random()) for x in xrange(100)]
# uncomment if scores must be unique
#scores = set(scores)
topten = sorted(scores, reverse=True)[:10]
print topten
Run Code Online (Sandbox Code Playgroud)
如果您需要防止列表中的重复分数使用一组.
这是获得前10个分数的"香草"方法,但它错过了优化的机会,这将对更大的数据集产生影响.
即,每当要求前10名时,不需要对整个列表进行排序,如果在添加分数时保持前十名分数列表.为此,也许可以保留2个清单; 完整列表和前10名,后来heapq@thijs van Dien建议的方法更优越.
使用该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]
Run Code Online (Sandbox Code Playgroud)
请注意,此模块具有更多有用的功能,仅请求最高/最低值等.这可以帮助您添加有关名称的行为.
实际上这个结构很常见,以至于它可用heapq.nlargest.但是,为了不存储所有结果,您必须将计算器建模为生成器,这有点高级.
from heapq import nlargest
def calculate_gen():
for x in [18, 85, 36, 57, 2, 45, 55, 1, 28, 73, 95, 38, 89, 15, 7, 61]:
yield x + 1 # Dummy calculation
top10 = nlargest(10, calculate_gen()) # [96, 90, 86, 74, 62, 58, 56, 46, 39, 37]
Run Code Online (Sandbox Code Playgroud)
奖金
以下是对每个关联名称组合使结果唯一的一些想法.
使用堆不会再削减它了,因为堆不能很好地定位任何不是绝对最小值/最大值的项,而我们感兴趣的是给定名称组合标准的某种局部最小值.
相反,您可以使用a dict来保持每个名称组合的最高值.首先,您需要将名称组合编码为不可变值,以使其作为键使用,并且因为名称的顺序无关紧要,所以决定一些顺序并坚持下去.我将使用字母字符串来保持简单.
在下面的代码中,每个结果都放在dict一个对于其名称组合唯一的位置 - 因此可能需要标准化 - 只要没有更好的结果.后来,前n个是根据每个组合的最高结果编译的.
from heapq import nlargest
calculations = [('ABC', 18), ('CDE', 85), ('BAC', 36), ('CDE', 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])
Run Code Online (Sandbox Code Playgroud)
这种方法的唯一问题可能是使用的内存量.由于有150个名称可以有551300(150选3)组合,你可能不得不决定时不时地清理它dict,这很简单.在循环中,检查其大小,dict如果它超过某个(仍然很大)数字,则组成当前的前n个并创建一个新的,最小的数字dict.此外,可以通过减少查找/调用的数量来应用一些微优化,例如不使用get和/或max.
如果您可以控制执行计算的顺序,那么所有这些都会容易得多.如果您知道接下来的1000个计算都是针对相同的名称组合,那么在将其添加到整体结果之前,您可以先找到最好的计算.
此外,真正大量的结果,最简单的方法实际上可能是最好的.只需将它们以方便的格式写入文件,然后对它们进行排序(首先按名称组合,然后按值反向排序),只对每个名称组合进行第一次出现(分组时很容易)并再次对结果进行排序,只需按值.
| 归档时间: |
|
| 查看次数: |
1284 次 |
| 最近记录: |