com.enterprisemath.math.statistics.IntervalFrequencyDistributionEstimator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of em-math Show documentation
Show all versions of em-math Show documentation
Advanced mathematical algorithms.
The newest version!
package com.enterprisemath.math.statistics;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.enterprisemath.math.probability.IntervalFrequencyDistribution;
import com.enterprisemath.math.statistics.observation.ObservationIterator;
import com.enterprisemath.math.statistics.observation.ObservationProvider;
import com.enterprisemath.utils.ValidationUtils;
import java.util.HashMap;
import java.util.Map;
/**
* This class is responsible for estimating the normal distribution mixture.
* Purpose of this class is to let the user to set high level limits and let the algorithm to do the rest.
* The whole algorithm works in the way that whole estimation starts with one component.
* Every iteration one component is selected and split. Then classic EM algorithm is invoked.
*
* @author radek.hecl
*
*/
public class IntervalFrequencyDistributionEstimator implements Estimator {
/**
* Builder object.
*/
public static class Builder {
/**
* Width of the unit.
*/
private Double unitWidth = 1d;
/**
* Sets unit width.
*
* @param unitWidth unit width
* @return this instance
*/
public Builder setUnitWidth(double unitWidth) {
this.unitWidth = unitWidth;
return this;
}
/**
* Builds the result object.
*
* @return created object
*/
public IntervalFrequencyDistributionEstimator build() {
return new IntervalFrequencyDistributionEstimator(this);
}
}
/**
* Width of the unit.
*/
private Double unitWidth;
/**
* Creates new instance.
*
* @param builder builder object
*/
public IntervalFrequencyDistributionEstimator(Builder builder) {
unitWidth = builder.unitWidth;
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardPositiveDouble(unitWidth, "unitWidth must be positive");
}
@Override
public IntervalFrequencyDistribution estimate(ObservationProvider observations) {
Map freqs = new HashMap();
ObservationIterator iterator = observations.getIterator();
while (iterator.isNextAvailable()) {
double x = iterator.getNext();
int id = getIntervalId(x);
if (freqs.containsKey(id)) {
freqs.put(id, freqs.get(id) + 1);
}
else {
freqs.put(id, 1);
}
}
double fact = (double)iterator.getNumIterated() * unitWidth;
IntervalFrequencyDistribution.Builder res = new IntervalFrequencyDistribution.Builder();
res.setUnitWidth(unitWidth);
for (int id : freqs.keySet()) {
res.setUnitValue(id, freqs.get(id) / fact);
}
return res.build();
}
/**
* Returns interval id.
*
* @param x random value
* @return interval id
*/
private int getIntervalId(double x) {
double did = Math.abs(x) / unitWidth;
int id = (int) did;
if (x < 0) {
if (did != (double) id) {
id = id + 1;
}
id = -id;
}
return id;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}