Minor cleanup of mean and variance

This commit is contained in:
Ozzie Gooen 2020-04-19 21:04:50 +01:00
parent 0fd5e2dcdb
commit f247f65478
4 changed files with 121 additions and 110 deletions

View File

@ -194,10 +194,10 @@ describe("Shape", () => {
0.9, 0.9,
); );
makeTest("integralEndY", T.Integral.sum(~cache=None, discrete), 1.0); makeTest("integralEndY", T.Integral.sum(~cache=None, discrete), 1.0);
makeTest("mean", T.getMean(discrete), 3.9); makeTest("mean", T.mean(discrete), 3.9);
makeTestCloseEquality( makeTestCloseEquality(
"variance", "variance",
T.getVariance(discrete), T.variance(discrete),
5.89, 5.89,
~digits=7, ~digits=7,
); );
@ -393,25 +393,25 @@ describe("Shape", () => {
makeTestCloseEquality( makeTestCloseEquality(
"Mean of a normal", "Mean of a normal",
T.getMean(normalShape), T.mean(normalShape),
mean, mean,
~digits=2, ~digits=2,
); );
makeTestCloseEquality( makeTestCloseEquality(
"Variance of a normal", "Variance of a normal",
T.getVariance(normalShape), T.variance(normalShape),
variance, variance,
~digits=1, ~digits=1,
); );
makeTestCloseEquality( makeTestCloseEquality(
"Mean of a lognormal", "Mean of a lognormal",
T.getMean(lognormalShape), T.mean(lognormalShape),
mean, mean,
~digits=2, ~digits=2,
); );
makeTestCloseEquality( makeTestCloseEquality(
"Variance of a lognormal", "Variance of a lognormal",
T.getVariance(lognormalShape), T.variance(lognormalShape),
variance, variance,
~digits=0, ~digits=0,
); );

View File

@ -124,73 +124,87 @@ let table = (distPlus, x) => {
</div>; </div>;
}; };
let percentiles = distPlus => { let percentiles = distPlus => {
<table className="table-auto text-sm"> <div>
<thead> <table className="table-auto text-sm">
<tr> <thead>
<td className="px-4 py-2"> {"1" |> ReasonReact.string} </td> <tr>
<td className="px-4 py-2"> {"5" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"1" |> ReasonReact.string} </td>
<td className="px-4 py-2"> {"25" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"5" |> ReasonReact.string} </td>
<td className="px-4 py-2"> {"50" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"25" |> ReasonReact.string} </td>
<td className="px-4 py-2"> {"75" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"50" |> ReasonReact.string} </td>
<td className="px-4 py-2"> {"95" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"75" |> ReasonReact.string} </td>
<td className="px-4 py-2"> {"99" |> ReasonReact.string} </td> <td className="px-4 py-2"> {"95" |> ReasonReact.string} </td>
</tr> <td className="px-4 py-2"> {"99" |> ReasonReact.string} </td>
</thead> <td className="px-4 py-2"> {"99.999" |> ReasonReact.string} </td>
<tbody> </tr>
<tr> </thead>
<td className="px-4 py-2 border"> <tbody>
{distPlus <tr>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.01) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.01)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.05) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.05)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.25) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.25)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.5) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.5)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.75) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.75)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.95) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.95)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.99) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.99)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.999) <td className="px-4 py-2 border">
|> showFloat} {distPlus
</td> |> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.99999)
<td className="px-4 py-2 border"> |> showFloat}
{distPlus </td>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.9999) </tr>
|> showFloat} </tbody>
</td> </table>
<td className="px-4 py-2 border"> <table className="table-auto text-sm">
{distPlus <thead>
|> Distributions.DistPlus.T.Integral.yToX(~cache=None, 0.99999) <tr>
|> showFloat} <td className="px-4 py-2"> {"mean" |> ReasonReact.string} </td>
</td> <td className="px-4 py-2">
</tr> {"standard deviation" |> ReasonReact.string}
</tbody> </td>
</table>; <td className="px-4 py-2"> {"variance" |> ReasonReact.string} </td>
</tr>
</thead>
<tbody>
<tr>
<td className="px-4 py-2 border">
{distPlus |> Distributions.DistPlus.T.mean |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> Distributions.DistPlus.T.variance |> showFloat}
</td>
</tr>
</tbody>
</table>
</div>;
}; };
let adjustBoth = discreteProbabilityMass => { let adjustBoth = discreteProbabilityMass => {

View File

@ -18,8 +18,8 @@ module type dist = {
let integralXtoY: (~cache: option(integral), float, t) => float; let integralXtoY: (~cache: option(integral), float, t) => float;
let integralYtoX: (~cache: option(integral), float, t) => float; let integralYtoX: (~cache: option(integral), float, t) => float;
let getMean: t => float; let mean: t => float;
let getVariance: t => float; let variance: t => float;
}; };
module Dist = (T: dist) => { module Dist = (T: dist) => {
@ -38,8 +38,8 @@ module Dist = (T: dist) => {
let toDiscrete = T.toDiscrete; let toDiscrete = T.toDiscrete;
let toScaledContinuous = T.toScaledContinuous; let toScaledContinuous = T.toScaledContinuous;
let toScaledDiscrete = T.toScaledDiscrete; let toScaledDiscrete = T.toScaledDiscrete;
let getMean = T.getMean; let mean = T.mean;
let getVariance = T.getVariance; let variance = T.variance;
// TODO: Move this to each class, have use integral to produce integral in DistPlus class. // TODO: Move this to each class, have use integral to produce integral in DistPlus class.
let scaleBy = (~scale=1.0, t: t) => t |> mapY((r: float) => r *. scale); let scaleBy = (~scale=1.0, t: t) => t |> mapY((r: float) => r *. scale);
@ -141,7 +141,7 @@ module Continuous = {
let toScaledContinuous = t => Some(t); let toScaledContinuous = t => Some(t);
let toScaledDiscrete = _ => None; let toScaledDiscrete = _ => None;
let getMean = (t: t) => { let mean = (t: t) => {
let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0; let indefiniteIntegralStepwise = (p, h1) => h1 *. p ** 2.0 /. 2.0;
let indefiniteIntegralLinear = (p, a, b) => let indefiniteIntegralLinear = (p, a, b) =>
a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0; a *. p ** 2.0 /. 2.0 +. b *. p ** 3.0 /. 3.0;
@ -151,10 +151,10 @@ module Continuous = {
t, t,
); );
}; };
let getVariance = (t: t): float => let variance = (t: t): float =>
XYShape.Analysis.getVarianceDangerously( XYShape.Analysis.getVarianceDangerously(
t, t,
getMean, mean,
XYShape.Analysis.getMeanOfSquaresContinuousShape, XYShape.Analysis.getMeanOfSquaresContinuousShape,
); );
}); });
@ -229,12 +229,12 @@ module Discrete = {
|> Continuous.getShape |> Continuous.getShape
|> XYShape.YtoX.linear(f); |> XYShape.YtoX.linear(f);
let getMean = (t: t): float => let mean = (t: t): float =>
E.A.reducei(t.xs, 0.0, (acc, x, i) => acc +. x *. t.ys[i]); E.A.reducei(t.xs, 0.0, (acc, x, i) => acc +. x *. t.ys[i]);
let getVariance = (t: t): float => { let variance = (t: t): float => {
let getMeanOfSquares = t => let getMeanOfSquares = t =>
getMean(XYShape.Analysis.squareXYShape(t)); mean(XYShape.Analysis.squareXYShape(t));
XYShape.Analysis.getVarianceDangerously(t, getMean, getMeanOfSquares); XYShape.Analysis.getVarianceDangerously(t, mean, getMeanOfSquares);
}; };
}); });
}; };
@ -408,36 +408,36 @@ module Mixed = {
}; };
}; };
let getMean = (t: t): float => { let mean = (t: t): float => {
let discreteProbabilityMassFraction = let discreteProbabilityMassFraction =
t.discreteProbabilityMassFraction; t.discreteProbabilityMassFraction;
switch (discreteProbabilityMassFraction) { switch (discreteProbabilityMassFraction) {
| 1.0 => Discrete.T.getMean(t.discrete) | 1.0 => Discrete.T.mean(t.discrete)
| 0.0 => Continuous.T.getMean(t.continuous) | 0.0 => Continuous.T.mean(t.continuous)
| _ => | _ =>
Discrete.T.getMean(t.discrete) Discrete.T.mean(t.discrete)
*. discreteProbabilityMassFraction *. discreteProbabilityMassFraction
+. Continuous.T.getMean(t.continuous) +. Continuous.T.mean(t.continuous)
*. (1.0 -. discreteProbabilityMassFraction) *. (1.0 -. discreteProbabilityMassFraction)
}; };
}; };
let getVariance = (t: t): float => { let variance = (t: t): float => {
let discreteProbabilityMassFraction = let discreteProbabilityMassFraction =
t.discreteProbabilityMassFraction; t.discreteProbabilityMassFraction;
let getMeanOfSquares = (t: t) => { let getMeanOfSquares = (t: t) => {
Discrete.T.getMean(XYShape.Analysis.squareXYShape(t.discrete)) Discrete.T.mean(XYShape.Analysis.squareXYShape(t.discrete))
*. t.discreteProbabilityMassFraction *. t.discreteProbabilityMassFraction
+. XYShape.Analysis.getMeanOfSquaresContinuousShape(t.continuous) +. XYShape.Analysis.getMeanOfSquaresContinuousShape(t.continuous)
*. (1.0 -. t.discreteProbabilityMassFraction); *. (1.0 -. t.discreteProbabilityMassFraction);
}; };
switch (discreteProbabilityMassFraction) { switch (discreteProbabilityMassFraction) {
| 1.0 => Discrete.T.getVariance(t.discrete) | 1.0 => Discrete.T.variance(t.discrete)
| 0.0 => Continuous.T.getVariance(t.continuous) | 0.0 => Continuous.T.variance(t.continuous)
| _ => | _ =>
XYShape.Analysis.getVarianceDangerously( XYShape.Analysis.getVarianceDangerously(
t, t,
getMean, mean,
getMeanOfSquares, getMeanOfSquares,
) )
}; };
@ -547,18 +547,18 @@ module Shape = {
Continuous.T.mapY(fn), Continuous.T.mapY(fn),
)); ));
let getMean = (t: t): float => let mean = (t: t): float =>
switch (t) { switch (t) {
| Mixed(m) => Mixed.T.getMean(m) | Mixed(m) => Mixed.T.mean(m)
| Discrete(m) => Discrete.T.getMean(m) | Discrete(m) => Discrete.T.mean(m)
| Continuous(m) => Continuous.T.getMean(m) | Continuous(m) => Continuous.T.mean(m)
}; };
let getVariance = (t: t): float => let variance = (t: t): float =>
switch (t) { switch (t) {
| Mixed(m) => Mixed.T.getVariance(m) | Mixed(m) => Mixed.T.variance(m)
| Discrete(m) => Discrete.T.getVariance(m) | Discrete(m) => Discrete.T.variance(m)
| Continuous(m) => Continuous.T.getVariance(m) | Continuous(m) => Continuous.T.variance(m)
}; };
}); });
}; };
@ -674,8 +674,8 @@ module DistPlus = {
let integralYtoX = (~cache as _, f, t: t) => { let integralYtoX = (~cache as _, f, t: t) => {
Shape.T.Integral.yToX(~cache=Some(t.integralCache), f, toShape(t)); Shape.T.Integral.yToX(~cache=Some(t.integralCache), f, toShape(t));
}; };
let getMean = (t: t) => Shape.T.getMean(t.shape); let mean = (t: t) => Shape.T.mean(t.shape);
let getVariance = (t: t) => Shape.T.getVariance(t.shape); let variance = (t: t) => Shape.T.variance(t.shape);
}); });
}; };

View File

@ -347,14 +347,11 @@ module Analysis = {
}; };
let getVarianceDangerously = let getVarianceDangerously =
(t: 't, getMean: 't => float, getMeanOfSquares: 't => float): float => { (t: 't, mean: 't => float, getMeanOfSquares: 't => float): float => {
let meanSquared = getMean(t) ** 2.0; let meanSquared = mean(t) ** 2.0;
let meanOfSquares = getMeanOfSquares(t); let meanOfSquares = getMeanOfSquares(t);
meanOfSquares -. meanSquared; meanOfSquares -. meanSquared;
}; };
let squareXYShape = (t): DistTypes.xyShape => { let squareXYShape = T.mapX(x => x ** 2.0)
...t,
xs: E.A.fmap(x => x ** 2.0, t.xs),
};
}; };