【问题标题】:Best way to calculate max diff's between items in a dictionary计算字典中项目之间最大差异的最佳方法
【发布时间】:2018-11-19 02:50:35
【问题描述】:

作为使用 Quandl 证券交易所数据的练习的一部分,我被要求计算 2017 年特定股票两个交易日之间收盘价的最大变化。我想出了不同的方法并对其进行计时。我期待 itertools.islice 更快,但事实并非如此。 (我的期望是由this SO answer 设定的) 要添加其他详细信息,我想打印出两个交易日期之间发生最大变化的日期,因此我还需要日期信息 - 最初我只找到了带有 for 循环的解决方案。

几个问题:

  • 我是否正确地接近了时间 - 确保唯一的事情在 单元格是我想要计时的代码等?
  • 结果的主要原因是我的字典中只有 255 个项目,所以本地资源 不征税并且加载完整列表很简单?

我正在使用 here 提供的 Jupyter 笔记本 - 这个问题与 Q5 有关。

我的数据是一个命名元组的字典:

{'2017-12-28': Tradeday(date='2017-12-28', open=51.65, high=51.82, low=51.43, close=51.6, change=None, traded_vol=40660.0, turn_over=2099024.0, last_price=None, d_trad_unit=None, d_turnover=None),
 '2017-12-29': Tradeday(date='2017-12-29', open=51.76, high=51.94, low=51.45, close=51.76, change=None, traded_vol=34640.0, turn_over=1792304.0, last_price=None, d_trad_unit=None, d_turnover=None)}

然后我将其分类为 OrderedDict:

o_data = OrderedDict(sorted(data.items(), key=lambda t:t[0]))

方法 4 - 将数据扁平化为 (k,v) 元组列表并在一个范围内迭代:

od_list = list(o_data.items())
max_change, max_st, max_ed  = 0, '', ''

for i in range(len(o_data)-1):
    change = abs(od_list[i][1].close-od_list[i+1][1].close)
    if change > max_change:
        max_change, max_st, max_ed = change, od_list[i][1].date, od_list[i+1][1].date

在单元格上使用 %%timeit 我得到了这些结果:

117 µs ± 2.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

方法 5 - 使用枚举并避免在内存中创建列表

mx, st, en = 0, '', ''
for i, v in enumerate(o_data.values()):
    if i < len(o_data)-1:
        ch = abs(v.close-next(islice(o_data.values(), i+1, i+2)).close)
        if ch > mx:
            mx, st, en = ch, v.date, next(islice(o_data.values(), i+1, i+2)).date

在单元格上使用 %%timeit 我得到了这些结果:

1.55 ms ± 12.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

编辑:(方法名称/编号已更新以匹配我在性能笔记本中使用的那些)

【问题讨论】:

  • 你试过max(abs(u.close-v.close) for u,v in zip(o_data.values(),o_data.values()[1:]))吗?
  • 感谢您的快速回复@DyZ 现在只是尝试一下 - 得到 'odict_values' 对象不可下标...max(abs(u.close-v.close) for u,v in zip(list(o_data.values()),list(o_data.values())[1:])) 工作....虽然我仍然需要 for 循环来获取在范围的开始日期和结束日期对吗?
  • 你说你只需要最大的变化,而不是日期。如果您需要其他内容,请更新您的问题。
  • 是的 - 添加了额外的细节来阐明为什么我有三个变量 max_change, max_st, max_ed = 0, '', ''mx, st, en = 0, '', ''
  • 再次感谢 DyZ - 我能够扩展您的建议以使用 zip() 来获取我想要的日期值。 max([(abs(t.close-p.close), t.date, p.date) for t, p in zip(list(o_data.values()),list(o_data.values())[1:])])

标签: python python-3.x


【解决方案1】:

非常感谢让我走上正轨的 DyZ,我已经回答了我自己的问题:

我想出了如何在一行理解中获取日期:

max([(abs(t.close-p.close), t.date, p.date) for t, p in zip(list(o_data.values()),list(o_data.values())[1:])], key=lambda x: x[0])

简化为最大值作用于元组的第一个元素

max([(abs(t.close-p.close), t.date, p.date) for t, p in zip(list(o_data.values()),list(o_data.values())[1:])])

我还探索了我的性能问题并创建了这个 Jupyter 笔记本:Q5 Performance

简单的内存列表(方法 4)在 255 天的数据中运行良好,但是当我将其增加到 4643 天的数据时,它的速度显着降低。使用 islice 的枚举(方法 5)几乎没有减慢速度,并且对于更大的数据集,它比简单的内存列表或单行列表理解(方法 3)更快。

(方法名称/编号已更新以匹配我在性能笔记本中使用的那些)

如果有人想在观察到的表演背后添加一些理论,我会很高兴!

【讨论】:

    猜你喜欢
    • 2019-10-06
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 2021-11-27
    • 2020-11-12
    • 2021-06-03
    相关资源
    最近更新 更多