/// <summary> /// Estimates the specified quantile /// </summary> /// <param name="quantile">The quantile to esimtate. Must be between 0 and 1.</param> /// <returns>The value for the estimated quantile</returns> public double Quantile(double quantile) { if (quantile < 0 || quantile > 1) { throw new ArgumentOutOfRangeException("Quantile must be between 0 and 1"); } if (_centroids.Count == 0) { throw new InvalidOperationException("Cannot call Quantile() method until first Adding values to the digest"); } if (_centroids.Count == 1) { return(_centroids.First().Value.Mean); } int i = 0; double t = 0; double q = quantile * _count; Centroid last = null; foreach (Centroid centroid in _centroids.Values) { last = centroid; double k = centroid.Count; if (q < t + k) { double delta; if (i == 0) { Centroid successor = _centroids.Successor(centroid.Mean).Value; delta = successor.Mean - centroid.Mean; } else if (i == _centroids.Count - 1) { Centroid predecessor = _centroids.Predecessor(centroid.Mean).Value; delta = centroid.Mean - predecessor.Mean; } else { Centroid successor = _centroids.Successor(centroid.Mean).Value; Centroid predecessor = _centroids.Predecessor(centroid.Mean).Value; delta = (successor.Mean - predecessor.Mean) / 2; } double estimated = centroid.Mean + ((q - t) / k - .5) * delta; // If estimated value is higher than max, return max return(Math.Min(estimated, this.Max)); } t += k; i++; } return(last.Mean); }
private IEnumerable <Centroid> GetClosestCentroids(double x) { C5.KeyValuePair <double, Centroid> successor; C5.KeyValuePair <double, Centroid> predecessor; if (!_centroids.TryWeakSuccessor(x, out successor)) { yield return(_centroids.Predecessor(x).Value); yield break; } if (successor.Value.Mean == x || !_centroids.TryPredecessor(x, out predecessor)) { yield return(successor.Value); yield break; } double sDiff = Math.Abs(successor.Value.Mean - x); double pDiff = Math.Abs(successor.Value.Mean - x); if (sDiff < pDiff) { yield return(successor.Value); } else if (pDiff < sDiff) { yield return(predecessor.Value); } else { yield return(successor.Value); yield return(predecessor.Value); } }