我正在Clojure中构建一个系统,它实时消耗事件并根据最近收到的类似消息对其进行操作。我想使用基于牛顿冷却的新近度分数来实现这一点。
换句话说,当一个事件到来时,我希望能够为它分配一个1.0之间的分数(以前从未发生过,或牛顿方程中的“环境温度”)和10.0(热烫热,已发生过几次)过去一分钟。)
我对这个数据结构的含义有一个模糊的概念 - 每个“事件类型”都是一个映射键,每个映射值都应该包含一些先前事件的时间戳集,也许还有当前“热量”的运行平均值“对于那种事件类型,但我无法弄清楚如何开始实施。具体来说,我无法弄清楚如何从牛顿的实际方程出发,这是非常通用的,并将其应用于这种特定情况。
有没有人有任何指针?有人会建议一个更简单的“新近度分数算法”让我开始,可以用牛顿冷却的方式取而代之吗?
编辑:这是一些clojure代码!它将事件称为字母,但显然可以重新用于处理任何其他类型的对象。
(ns heater.core
(:require [clojure.contrib.generic.math-functions :as math]))
(def letter-recency-map (ref {}))
(def MIN-TEMP 1.0)
(def MAX-TEMP 10.0)
;; Cooling time is 15 seconds
(def COOLING-TIME 15000)
;; Events required to reach max heat
(def EVENTS-TO-HEAT 5.0)
(defn temp-since [t since now]
(+
MIN-TEMP
(*
(math/exp (/
(- (- now since))
COOLING-TIME))
(- t MIN-TEMP))))
(defn temp-post-event [temp-pre-event]
(+ temp-pre-event
(/
(- MAX-TEMP temp-pre-event)
EVENTS-TO-HEAT)))
(defn get-letter-heat [letter]
(dosync
(let [heat-record (get (ensure letter-recency-map) letter)]
(if (= heat-record nil)
(do
(alter letter-recency-map conj {letter {:time (System/currentTimeMillis) :heat 1.0}})
MIN-TEMP)
(let [now (System/currentTimeMillis)
new-temp-cooled (temp-since (:heat heat-record) (:time heat-record) now)
new-temp-event (temp-post-event new-temp-cooled)]
(alter letter-recency-map conj {letter {:time now :heat new-temp-event}})
new-temp-event)))))
答案 0 :(得分:5)
在没有任何事件的情况下,冷却方程的解是指数衰减。假设T_0
是冷却期开始时的温度,dt
是时间步长(根据系统时间或其他方式计算),因为您将温度评估为T_0
:
T_no_events(dt) = T_min + (T_0 - T_min)*exp(- dt / t_cooling)
由于您的事件是离散的冲动,并且您有最高温度,因此您希望每个事件都有一个给定的比率:
T_post_event = T_pre_event + (T_max - T_pre_event) / num_events_to_heat
一些注意事项:
t_cooling
是让事情冷却的时间1/e = 1/(2.718...)
。
num_events_to_heat
是具有与T_max
相当的效果所需的事件数。它应该是一个中等大的正值(比如5.0
或更多?)。请注意,如果num_events_to_heat==1.0
,每个事件都会将温度重置为T_max
,这不是很有趣,因此该值至少应该大于1。
理论上,加热和冷却都不应该分别达到最高和最低温度(假设参数设置如上,并且你从两者之间开始)。但在实践中,过程的指数性质应该足够接近,因为没有区别......
要实现此功能,您只需存储上次更新的时间戳和温度。当您收到活动时,请执行冷却步骤,然后执行加热事件,并使用新的温度和时间戳进行更新。
请注意,只读查询不需要更新:您可以计算自上次更新以来的散热。