org.opentripplanner.util.stats.DiscreteDistribution Maven / Gradle / Ivy
package org.opentripplanner.util.stats;
import java.text.MessageFormat;
import com.google.common.collect.Multiset;
import com.google.common.collect.SortedMultiset;
import com.google.common.collect.TreeMultiset;
interface Quantifiable> extends Comparable {
public double doubleValue();
}
/**
* A discrete distribution on K (aka frequency).
*/
public class DiscreteDistribution> {
public static class NumberQuantifiable implements
Quantifiable> {
private K num;
public NumberQuantifiable(K num) {
this.num = num;
}
@Override
public int hashCode() {
return num.hashCode();
}
@Override
public boolean equals(Object another) {
if (another instanceof NumberQuantifiable) {
@SuppressWarnings("unchecked")
NumberQuantifiable other = (NumberQuantifiable) another;
return other.num.equals(this.num);
}
return false;
}
@Override
public int compareTo(NumberQuantifiable o) {
// This should be safe, even for integers
return Double.compare(this.num.doubleValue(), o.num.doubleValue());
}
@Override
public double doubleValue() {
return num.doubleValue();
}
@Override
public String toString() {
return num.toString();
}
}
public static class LogQuantifiable implements
Quantifiable> {
private int log;
private double mult;
private K k;
public LogQuantifiable(K k, double mult) {
this.mult = mult;
this.k = k;
log = (int) Math.round(Math.log(k.doubleValue()) * mult);
}
@Override
public int hashCode() {
return log;
}
@Override
public boolean equals(Object another) {
if (another instanceof LogQuantifiable) {
@SuppressWarnings("unchecked")
LogQuantifiable anotherLog = (LogQuantifiable) another;
return anotherLog.log == this.log;
}
return false;
}
@Override
public int compareTo(LogQuantifiable o) {
// Do not compare on k here!
return Integer.compare(log, o.log);
}
@Override
public double doubleValue() {
return k.doubleValue();
}
@Override
public String toString() {
double min = Math.exp(log / mult);
double max = Math.exp((log + 1) / mult);
return String.format("%.2f-%.2f", min, max);
}
}
public static class ConstantQuantifiable> implements
Quantifiable> {
private K k;
public ConstantQuantifiable(K k) {
this.k = k;
}
@Override
public int hashCode() {
return k.hashCode();
}
@Override
public boolean equals(Object another) {
if (another instanceof ConstantQuantifiable) {
@SuppressWarnings("unchecked")
ConstantQuantifiable other = (ConstantQuantifiable) another;
return other.k.equals(this.k);
}
return false;
}
@Override
public int compareTo(ConstantQuantifiable o) {
return k.compareTo(o.k);
}
@Override
public double doubleValue() {
return 1.0;
}
@Override
public String toString() {
return k.toString();
}
}
private double totK = 0.0;
private SortedMultiset distribution = TreeMultiset.create();
public void add(K k) {
totK += k.doubleValue();
distribution.add(k, 1);
}
public void add(K k, String sample) {
totK += k.doubleValue();
if (distribution.count(k) == 0) {
System.out.println(k.doubleValue() + " => " + sample);
}
distribution.add(k, 1);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
int totCount = distribution.size();
int minCount = Integer.MAX_VALUE;
int maxCount = 0;
for (Multiset.Entry e : distribution.entrySet()) {
int count = e.getCount();
if (count < minCount)
minCount = count;
if (count > maxCount)
maxCount = count;
}
sb.append(String.format("K: Total: %.02f, avg: %.02f, min: %s, max: %s\n", totK, totK * 1.0
/ totCount, distribution.firstEntry().getElement(), distribution.lastEntry()
.getElement()));
sb.append(String.format("C: Total: %d, min: %d, max: %d\n", totCount, minCount, maxCount));
for (Multiset.Entry e : distribution.entrySet()) {
sb.append(MessageFormat.format("{0} : {1} {2}\n", e.getElement().toString(),
chart(e.getCount(), maxCount, 60), e.getCount()));
}
sb.append("----------------------------------------------------------------");
return sb.toString();
}
private String chart(int x, int xMax, int len) {
StringBuffer retval = new StringBuffer();
for (int i = 0; i < Math.round(x * 1.0 * len / xMax); i++)
retval.append("*");
return retval.toString();
}
}