YOUSEFUL / DELPHI / COMPONENTS

TAtlasStats

Statistics without a chart: mean, deviation, quantiles, box statistics, histograms, correlation, polynomial fits and smoothing.

Class Unit Atlas.PlotStats · Product Atlas Plot Pro

Description

Plain statistics with no UI dependency. Every function is a class function ... static, so call them on the class (TAtlasStats.Mean(Values)) without creating an object. The box plot and the analysis helpers use the same functions, so a chart and your own code always agree.

Each function except Sorted validates its input and raises EAtlasPlotError (unit Atlas.PlotAxis) instead of returning NaN: too few values, NaN, infinite values and magnitudes above 1E100 are rejected, as are out-of-range arguments such as a quantile fraction above 1. Inputs are never modified. The functions keep no state and can be called from any thread.

Definitions: quantiles interpolate linearly between closest ranks ("type 7"); the standard deviation is the sample one (n - 1); whiskers end at the most extreme values within 1.5 interquartile ranges of the box; histogram bins are half open except the last; polynomial fits are least squares on arguments scaled to -1..1.

Members

MemberKindWhat it does
SortedmethodA sorted copy of Values, ascending; the input is not changed.
MeanmethodArithmetic mean.
StdDevmethodSample standard deviation (divides by n - 1).
QuantilemethodThe quantile at Fraction (0 to 1) by linear interpolation between closest ranks: position (n - 1) * Fraction in the sorted values (the common "type 7", as in spreadsheet QUARTILE.INC).
BoxmethodEverything a box plot needs: count, minimum, quartiles, median, maximum, mean, whiskers and outliers.
HistogrammethodCounts Values in Bins equal-width bins from the minimum to the maximum.
CorrelationmethodPearson's correlation coefficient r, from -1 to 1.
PolynomialFitmethodLeast-squares polynomial of degree 1 to 6 through the points (X[i], Y[i]), with its R squared.
ExponentialSmoothingmethodSimple exponential smoothing: the first result is the first value, and each later one moves Alpha of the way from the previous result towards the next value.

Methods

Sorted method

class function Sorted(const Values: TArray<Double>): TArray<Double>; static;

A sorted copy of Values, ascending; the input is not changed. Unlike the other functions it does not validate its input (an empty array gives an empty result).

pascal
Ordered := TAtlasStats.Sorted([3, 1, 2]);   // [1, 2, 3]

Mean method

class function Mean(const Values: TArray<Double>): Double; static;

Arithmetic mean. Needs at least one value. Computed as a running mean, so values near 1E100 do not overflow.

pascal
Value := TAtlasStats.Mean([1, 2, 3, 6]);   // 3

StdDev method

class function StdDev(const Values: TArray<Double>): Double; static;

Sample standard deviation (divides by n - 1). Needs at least two values; 0 when all are equal. Scaled internally so large values do not overflow.

pascal
Value := TAtlasStats.StdDev([2, 4, 4, 4, 5, 5, 7, 9]);   // Sqrt(32 / 7) = 2.138

Quantile method

class function Quantile(const Values: TArray<Double>; const Fraction: Double): Double; static;

The quantile at Fraction (0 to 1) by linear interpolation between closest ranks: position (n - 1) * Fraction in the sorted values (the common "type 7", as in spreadsheet QUARTILE.INC). The input need not be sorted. Needs at least one value; a fraction outside 0..1 or NaN raises.

pascal
Value := TAtlasStats.Quantile([4, 1, 3, 2], 0.25);   // 1.75

Box method

class function Box(const Values: TArray<Double>): TAtlasBoxStats; static;

Everything a box plot needs: count, minimum, quartiles, median, maximum, mean, whiskers and outliers. See TAtlasBoxStats. Needs at least one value; a single value gives a box of zero size.

pascal
Summary := TAtlasStats.Box([1, 2, 3, 4, 5, 6, 7, 8, 9, 40]);   // Q1 3.25, median 5.5, Q3 7.75, outlier 40

Histogram method

class function Histogram(const Values: TArray<Double>; Bins: Integer = 0): TAtlasHistogram; static;

Counts Values in Bins equal-width bins from the minimum to the maximum. Bins 0 chooses Sturges' rule, ceil(log2 n) + 1; otherwise 1 to 10000, and anything outside 0..10000 raises. Bins are half open, [edge, next edge), except the last, which includes the maximum. When all values are equal there is one bin of width one centred on them. See TAtlasHistogram.

pascal
Bars := TAtlasStats.Histogram([1, 2, 2, 3, 3, 3, 4, 4, 5], 4);   // counts 1, 2, 3, 3

Correlation method

class function Correlation(const X, Y: TArray<Double>): Double; static;

Pearson's correlation coefficient r, from -1 to 1. Both arrays need the same length, at least two values and some variation; otherwise EAtlasPlotError is raised.

pascal
R := TAtlasStats.Correlation([1, 2, 3, 4, 5], [2, 1, 4, 3, 5]);   // 0.8

PolynomialFit method

class function PolynomialFit(const X, Y: TArray<Double>; Degree: Integer): TAtlasPolynomial; static;

Least-squares polynomial of degree 1 to 6 through the points (X[i], Y[i]), with its R squared. Both arrays need the same length and at least Degree + 1 values, and there must be more distinct X values than the degree; otherwise EAtlasPlotError is raised ("A fit needs more distinct arguments than its degree"). The arguments are scaled to -1..1 before fitting, so date values (around 46,000) and other large arguments stay well conditioned. See TAtlasPolynomial.

pascal
Fit := TAtlasStats.PolynomialFit([-2, -1, 0, 1, 2], [9, 3, 1, 3, 9], 2);
Value := Fit.Evaluate(3);   // 19, since y = 2x² + 1

ExponentialSmoothing method

class function ExponentialSmoothing(const Values: TArray<Double>; const Alpha: Double): TArray<Double>; static;

Simple exponential smoothing: the first result is the first value, and each later one moves Alpha of the way from the previous result towards the next value. Alpha must be above 0 and at most 1 (1 returns a copy of the input); needs at least one value.

pascal
Smooth := TAtlasStats.ExponentialSmoothing([10, 20, 20, 0], 0.5);   // 10, 15, 17.5, 8.75

Examples

Summarise a sample

Quartiles, whiskers and outliers of a set of response times, with the rejection of bad input.

pascal
uses
  System.SysUtils, Atlas.PlotAxis, Atlas.PlotStats;

function Describe(const Times: TArray<Double>): string;
var Box: TAtlasBoxStats;
begin
  try
    Box := TAtlasStats.Box(Times);
    Result := Format('n=%d median=%.1f IQR=%.1f..%.1f whiskers=%.1f..%.1f outliers=%d sd=%.2f',
      [Box.Count, Box.Median, Box.Q1, Box.Q3, Box.LowWhisker, Box.HighWhisker, Length(Box.Outliers),
       TAtlasStats.StdDev(Times)]);
  except
    on E: EAtlasPlotError do Result := 'cannot describe: ' + E.Message;   // e.g. fewer than two values
  end;
end;

Fit a trend and extrapolate

A quadratic through daily values, evaluated one week beyond the data.

pascal
uses
  System.Math, Atlas.PlotStats;

function NextWeek(const Days, Sales: TArray<Double>; out RSquared: Double): Double;
var Fit: TAtlasPolynomial;
begin
  Fit := TAtlasStats.PolynomialFit(Days, Sales, 2);   // raises with fewer than three distinct days
  RSquared := Fit.RSquared;
  Result := Fit.Evaluate(MaxValue(Days) + 7);
end;

TAtlasBoxStats · TAtlasHistogram · TAtlasPolynomial · TAtlasPlotAnalysis · EAtlasPlotError

Also in Atlas Plot Pro

TAtlasBoxPlot · TAtlasHeatMap · TAtlasPolarPlot