Ben*_*ert 14 algorithm math clojure
我正在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)))))
Run Code Online (Sandbox Code Playgroud)
在没有任何事件的情况下,冷却方程的解是指数衰减.假设T_0是冷却期开始时的温度,并且dt是时间步长(根据系统时间或其他因素计算),因为您评估温度为T_0:
T_no_events(dt) = T_min + (T_0 - T_min)*exp(- dt / t_cooling)
Run Code Online (Sandbox Code Playgroud)
由于您的事件是离散的冲动,并且您具有最高温度,因此您希望每个事件具有给定的比率:
T_post_event = T_pre_event + (T_max - T_pre_event) / num_events_to_heat
Run Code Online (Sandbox Code Playgroud)
一些说明:
t_cooling是时候冷静下来的时间了1/e = 1/(2.718...).
num_events_to_heat是具有可比效果所需的事件数量T_max.它应该是一个中等大的正值(说5.0或更多?).请注意,如果num_events_to_heat==1.0每个事件都将温度重置为T_max,这不是很有趣,因此该值应该至少大于1.
从理论上讲,加热和冷却都不应该分别达到最高和最低温度(假设参数设置如上,并且你从两者之间的某处开始).但在实践中,过程的指数性质应该足够接近,因为没有区别......
要实现此功能,您只需存储上次更新的时间戳和温度.收到活动时,请执行冷却步骤,然后执行加热事件,并使用新的温度和时间戳进行更新.
请注意,只读查询不需要更新:您可以计算自上次更新以来的冷却.