我有一组有序的数据点存储为TreeSet<DataPoint>
。每个数据点都有position
和Set
个Event
个对象(HashSet<Event>
)。
有4种可能的Event
个对象A
,B
,C
和D
。每个DataPoint
都有2个,例如A
和C
,但集合中的第一个和最后一个DataPoint
对象除外,其中T
的大小为1。
我的算法是查找此集合中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是{{1} } {},http://mathbin.net/equations/105225_12.png是此DataPoint
的事件的Set
。
DataPoint
与Q
Event
的概率为:
http://mathbin.net/equations/105225_11.png
我用Java实现了这个算法:
q
所以要找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)
}
}
Q
x
q
的概率:
Double S1 = S(points);
points.add(Q);
Double S2 = S(points);
Double probability = S2/S1;
目前实施情况紧跟数学算法。然而,事实证明这并不是一个特别好的主意,因为f
会为每个DataPoint
调用两次。因此,对于http://mathbin.net/equations/105225_9.png,f
被调用两次,然后对于n-1
f
,对于之前的每个调用再次调用两次,依此类推。这会导致O(2^n)
的复杂性,考虑到每个DataPoints
中可能有超过1000 Set
,这非常糟糕。因为p()
独立于除了参数以外的所有参数,我已经包含了一个缓存函数,如果已经为这些参数计算了p()
,它只返回先前的结果,但这并不能解决固有的复杂性问题。我在这里遗漏了一些关于重复计算的东西,还是这个算法中不可避免的复杂性?
答案 0 :(得分:2)
你还需要在前2个参数上记忆f
(第3个参数总是通过,所以你不必担心这个)。这会将代码的时间复杂度从O(2 ^ n)减少到O(n)。
答案 1 :(得分:0)
更新:
由于如下所述,订单不能用于帮助优化必须使用的另一种方法。由于大多数P值将被多次计算(并且如上所述,这是昂贵的),因此一种优化将是缓存它们。我不确定最好的密钥是什么,但你可以想象改变代码如下:
....
private Map<String, Double> previousResultMap = new ....
private Double p(DataPoint right, Event rightEvent, DataPoint left, Event leftEvent) {
String key = // calculate unique key from inputs
Double previousResult = previousResultMap.get(key);
if (previousResult != null) {
return previousResult;
}
// do some stuff
previousResultMap.put(key, result);
return result;
}
这种方法应该有效地减少了大量的冗余计算 - 但是,因为你比我更了解数据,你需要确定设置密钥的最佳方法(即使String是最好的表示方式) )。
答案 2 :(得分:0)
感谢您的所有建议。我通过为已计算的P
和F
的值创建新的嵌套类来实现我的解决方案,然后使用HashMap
来存储结果。然后在计算发生之前查询HashMap
的结果;如果它存在则只返回结果,如果不存在则计算结果并将其添加到HashMap
。
最终产品看起来有点像这样:
public class ProbabilityCalculator {
private NavigableSet<DataPoint> points;
private ProbabilityCalculator(NavigableSet<DataPoint> points) {
this.points = points;
}
private static class P {
public final DataPoint left;
public final Event leftEvent;
public final DataPoint right;
public final Event rightEvent;
public P(DataPoint left, Event leftEvent, DataPoint right, Event rightEvent) {
this.left = left;
this.leftEvent = leftEvent;
this.right = right;
this.rightEvent = rightEvent;
}
public boolean equals(Object o) {
if(!(o instanceof P)) return false;
P p = (P) o;
if(!(this.leftEvent == null ? p.leftEvent == null : this.leftEvent.equals(p.leftEvent)))
return false;
if(!(this.rightEvent == null ? p.rightEvent == null : this.rightEvent.equals(p.rightEvent)))
return false;
return this.left.equals(p.left) && this.right.equals(p.right);
}
public int hashCode() {
int result = 93;
result = 31 * result + this.left.hashCode();
result = 31 * result + this.right.hashCode();
result = this.leftEvent != null ? 31 * result + this.leftEvent.hashCode() : 31 * result;
result = this.rightEvent != null ? 31 * result + this.rightEvent.hashCode() : 31 * result;
return result;
}
}
private Map<P, Double> usedPs = new HashMap<P, Double>();
private static class F {
public final DataPoint left;
public final Event leftEvent;
public final NavigableSet<DataPoint> dataPointsToLeft;
public F(DataPoint dataPoint, Event dataPointEvent, NavigableSet<DataPoint> dataPointsToLeft) {
this.dataPoint = dataPoint;
this.dataPointEvent = dataPointEvent;
this.dataPointsToLeft = dataPointsToLeft;
}
public boolean equals(Object o) {
if(!(o instanceof F)) return false;
F f = (F) o;
return this.dataPoint.equals(f.dataPoint) && this.dataPointEvent.equals(f.dataPointEvent) && this.dataPointsToLeft.equals(f.dataPointsToLeft);
}
public int hashCode() {
int result = 7;
result = 31 * result + this.dataPoint.hashCode();
result = 31 * result + this.dataPointEvent.hashCode();
result = 31 * result + this.dataPointsToLeft.hashCode();
return result;
}
}
private Map<F, Double> usedFs = new HashMap<F, Double>();
private Double p(DataPoint right, Event rightEvent, DataPoint left, Event leftEvent) {
P newP = new P(right, rightEvent, left, leftEvent);
if(this.usedPs.containsKey(newP)) return usedPs.get(newP);
// do some stuff
usedPs.put(newP, result);
return result;
}
private Double f(DataPoint right, Event rightEvent) {
NavigableSet<DataPoint> dataPointsToLeft = dataPoints.headSet(right, false);
F newF = new F(right, rightEvent, dataPointsToLeft);
if(usedFs.containsKey(newF)) return usedFs.get(newF);
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);
}
usedFs.put(newF, result)
return result;
}
public Double S() {
return f(points.last(), points.last().getRightNodeEvent(), points)
}
public static probabilityOfQ(DataPoint q, NavigableSet<DataPoint> points) {
ProbabilityCalculator pc = new ProbabilityCalculator(points);
Double S1 = S();
points.add(q);
Double S2 = S();
return S2/S1;
}
}