背景
我有一组有序的数据点,存储在一个 TreeSet<DataPoint>
中。每个数据点都有一个 position
和一个 Event
对象的 Set
(HashSet<Event>
)。
有 4 种可能的 Event
对象 A
、B
、C
和 D
。每个 DataPoint
都有其中的 2 个,例如 A
和 C
,除了集合中的第一个和最后一个 DataPoint
对象,它们只有大小为 1 的 T
。
我的算法是找到一个新的 DataPoint
Q
在位置 x
上具有 Event
q
在这个集合中的概率。
我通过计算此数据集的值 S
,然后将 Q
添加到集合中并再次计算 S
来实现这一点。然后,我将第二个 S
除以第一个,以分离新的 DataPoint
Q
的概率。
算法
计算 S
的公式如下:
http://mathbin.net/equations/105225_0.png
其中
http://mathbin.net/equations/105225_1.png
http://mathbin.net/equations/105225_2.png
对于 http://mathbin.net/equations/105225_3.png
以及
http://mathbin.net/equations/105225_4.png
http://mathbin.net/equations/105225_5.png是一个昂贵的概率函数,它只取决于其参数而不受其他影响(以及http://mathbin.net/equations/105225_6.png),http://mathbin.net/equations/105225_7.png是集合中的最后一个DataPoint
(右侧节点),http://mathbin.net/equations/105225_8.png是第一个DataPoint
(左侧节点),http://mathbin.net/equations/105225_9.png是不是节点的最右侧DataPoint
,http://mathbin.net/equations/105225_10.png是一个DataPoint
,http://mathbin.net/equations/105225_12.png是此DataPoint
的事件Set
。
因此,具有事件q
的Q
的概率为:
http://mathbin.net/equations/105225_11.png
实现
我用Java实现了这个算法:
public class ProbabilityCalculator {
private Double p(DataPoint right, Event rightEvent, DataPoint left, Event leftEvent) {
// do some stuff
}
private Double f(DataPoint right, Event rightEvent, NavigableSet<DataPoint> points) {
DataPoint left = points.lower(right);
Double result = 0.0;
if(left.isLefthandNode()) {
result = 0.25 * p(right, rightEvent, left, null);
} else if(left.isQ()) {
result = p(right, rightEvent, left, left.getQEvent()) * f(left, left.getQEvent(), points);
} else { // if M_k
for(Event leftEvent : left.getEvents())
result += p(right, rightEvent, left, leftEvent) * f(left, leftEvent, points);
}
return result;
}
public Double S(NavigableSet<DataPoint> points) {
return f(points.last(), points.last().getRightNodeEvent(), points)
}
}
因此,要找到在x
处概率为Q
的q
:
Double S1 = S(points);
points.add(Q);
Double S2 = S(points);
Double probability = S2/S1;
问题
目前的实现严格遵循数学算法。然而,在实践中,这并不是一个特别好的想法,因为对于每个 DataPoint
,f
会调用自身两次。所以对于http://mathbin.net/equations/105225_9.png,f
被调用两次,然后对于前面每个调用,n-1
又会再次调用两次 f
,依此类推。这导致复杂度为 O(2^n)
,考虑到每个 Set
中可能有超过 1000 个 DataPoints
,这相当糟糕。由于 p()
除了它的参数之外与其他一切都无关,因此我包括了一个缓存函数,如果已经为这些参数计算了 p()
,则它只返回先前的结果,但这并不能解决固有的复杂性问题。在重复计算方面,我是否漏掉了什么,或者这种算法的复杂性是不可避免的?
f
也缓存起来呢?只需将参数points
从函数参数移动到类成员即可。 - Dialecticuspoints
的子集存储到right
左侧,这将使缓存在将Q
添加到点之后仍然可以使用,一旦Q
已经在过程中被传递。 - bountiful