First step for GenericDistribution

This commit is contained in:
Ozzie Gooen 2020-02-15 19:44:18 +00:00
parent ab9c8726d6
commit 626b4f65c3
7 changed files with 264 additions and 94 deletions

View File

@ -1,62 +1,4 @@
type timeUnit = [
| `days
| `hours
| `milliseconds
| `minutes
| `months
| `quarters
| `seconds
| `weeks
| `years
];
type timeVector = {
zero: MomentRe.Moment.t,
unit: timeUnit,
};
type timePoint = {
timeVector,
value: float,
};
module TimePoint = {
let fromTimeVector = (timeVector, value): timePoint => {timeVector, value};
let toMoment = (timePoint: timePoint) => {
timePoint.timeVector.zero
|> MomentRe.Moment.add(
~duration=
MomentRe.duration(timePoint.value, timePoint.timeVector.unit),
);
};
let fromMoment = (timeVector: timeVector, moment: MomentRe.Moment.t) =>
MomentRe.diff(timeVector.zero, moment, timeVector.unit);
};
module RelativeTimePoint = {
type timeInVector =
| Time(MomentRe.Moment.t)
| XValue(float);
let toTime = (timeVector: timeVector, timeInVector: timeInVector) =>
switch (timeInVector) {
| Time(r) => r
| XValue(r) =>
timeVector.zero
|> MomentRe.Moment.add(~duration=MomentRe.duration(r, timeVector.unit))
};
let _timeToX = (time, timeStart, timeUnit) =>
MomentRe.diff(timeStart, time, timeUnit);
let toXValue = (timeVector: timeVector, timeInVector: timeInVector) =>
switch (timeInVector) {
| Time(r) => _timeToX(r, timeVector.zero, timeVector.unit)
| XValue(r) => r
};
};
open TimeTypes;
type t = {
timeVector,

View File

@ -0,0 +1,136 @@
type domainLimit = {
xPoint: float,
excludingProbabilityMass: float,
};
type domain =
| Complete
| LeftLimited(domainLimit)
| RightLimited(domainLimit)
| LeftAndRightLimited(domainLimit, domainLimit);
type continuousShape = {
xs: array(float),
ys: array(float),
};
type discreteShape = {
xs: array(float),
ys: array(float),
};
type mixedShape = {
continuous: continuousShape,
discrete: discreteShape,
discreteProbabilityMassFraction: float,
};
type pointsType =
| Mixed(mixedShape)
| Discrete(discreteShape)
| Continuous(continuousShape);
type generationSource =
| GuesstimatorString(string)
| Shape(pointsType);
type distributionUnit =
| Unspecified
| Time(TimeTypes.timeVector);
type probabilityType =
| Cdf
| Pdf
| Arbitrary;
type genericDistribution = {
generationSource,
probabilityType,
domain,
unit: distributionUnit,
};
module Shape = {
module Continuous = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
};
module Discrete = {
let fromArrays = (xs, ys): continuousShape => {xs, ys};
};
module Mixed = {
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
continuous,
discrete,
discreteProbabilityMassFraction,
};
module Builder = {
type assumption =
| ADDS_TO_1
| ADDS_TO_CORRECT_PROBABILITY;
type assumptions = {
continuous: assumption,
discrete: assumption,
discreteProbabilityMass: option(float),
};
let build = (~continuous, ~discrete, ~assumptions) =>
switch (assumptions) {
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: Some(r),
} =>
// TODO: Fix this, it's wrong :(
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: Some(r),
} =>
Some(
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
)
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_CORRECT_PROBABILITY,
discrete: ADDS_TO_1,
discreteProbabilityMass: None,
} =>
None
| {
continuous: ADDS_TO_1,
discrete: ADDS_TO_CORRECT_PROBABILITY,
discreteProbabilityMass: None,
} =>
None
| _ => None
};
};
};
};
module GenericDistribution = {
let make =
(
~generationSource,
~probabilityType=Pdf,
~domain=Complete,
~unit=Unspecified,
(),
)
: genericDistribution => {
generationSource,
probabilityType,
domain,
unit,
};
};

View File

@ -55,41 +55,41 @@ module Value = {
| SelectSingle(r) => r |> ReasonReact.string
| ConditionalArray(r) => "Array" |> ReasonReact.string
| Conditional(r) => r.name |> ReasonReact.string
| TimeLimitedDomainCdfLazy(r) =>
let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000));
let cdf = timeLimited.limitedDomainCdf.distribution;
<>
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
<Chart
height=100
data={
cdf
|> CdfLibrary.Distribution.toPdf
|> Types.ContinuousDistribution.toJs
}
/>
{FloatCdf.logNormal(50., 20.) |> ReasonReact.string}
</>;
| TimeLimitedDomainCdfLazy(r) => <div />
// let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000));
// let cdf = timeLimited.limitedDomainCdf.distribution;
// <>
// <Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
// <Chart
// height=100
// data={
// cdf
// |> CdfLibrary.Distribution.toPdf
// |> Types.ContinuousDistribution.toJs
// }
// />
// {FloatCdf.logNormal(50., 20.) |> ReasonReact.string}
// </>;
| TimeLimitedDomainCdf(r) =>
let cdf: Types.ContinuousDistribution.t =
r.limitedDomainCdf.distribution;
<>
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
</>;
| FloatCdf(r) =>
let cdf: Types.ContinuousDistribution.t =
CdfLibrary.Distribution.fromString(r, 2000);
<>
<Chart
height=100
data={
cdf
|> CdfLibrary.Distribution.toPdf
|> Types.ContinuousDistribution.toJs
}
/>
{r |> ReasonReact.string}
</>;
| FloatCdf(r) => <div />
// let cdf: Types.MixedDistribution.t =
// CdfLibrary.Distribution.fromString(r, 2000);
// <>
// <Chart
// height=100
// data={
// cdf
// |> CdfLibrary.Distribution.toPdf
// |> Types.ContinuousDistribution.toJs
// }
// />
// {r |> ReasonReact.string}
// </>;
| Probability(r) =>
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string
| DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string

59
src/lib/TimeTypes.re Normal file
View File

@ -0,0 +1,59 @@
type timeUnit = [
| `days
| `hours
| `milliseconds
| `minutes
| `months
| `quarters
| `seconds
| `weeks
| `years
];
type timeVector = {
zero: MomentRe.Moment.t,
unit: timeUnit,
};
type timePoint = {
timeVector,
value: float,
};
module TimePoint = {
let fromTimeVector = (timeVector, value): timePoint => {timeVector, value};
let toMoment = (timePoint: timePoint) => {
timePoint.timeVector.zero
|> MomentRe.Moment.add(
~duration=
MomentRe.duration(timePoint.value, timePoint.timeVector.unit),
);
};
let fromMoment = (timeVector: timeVector, moment: MomentRe.Moment.t) =>
MomentRe.diff(timeVector.zero, moment, timeVector.unit);
};
module RelativeTimePoint = {
type timeInVector =
| Time(MomentRe.Moment.t)
| XValue(float);
let toTime = (timeVector: timeVector, timeInVector: timeInVector) =>
switch (timeInVector) {
| Time(r) => r
| XValue(r) =>
timeVector.zero
|> MomentRe.Moment.add(~duration=MomentRe.duration(r, timeVector.unit))
};
let _timeToX = (time, timeStart, timeUnit) =>
MomentRe.diff(timeStart, time, timeUnit);
let toXValue = (timeVector: timeVector, timeInVector: timeInVector) =>
switch (timeInVector) {
| Time(r) => _timeToX(r, timeVector.zero, timeVector.unit)
| XValue(r) => r
};
};

View File

@ -59,7 +59,7 @@ module DiscreteDistribution = {
};
module MixedDistribution = {
type distribution = {
type t = {
discrete: DiscreteDistribution.t,
continuous: ContinuousDistribution.t,
};

View File

@ -39,8 +39,35 @@ module JS = {
external scoreNonMarketCdfCdf: (int, distJs, distJs, float) => distJs =
"scoreNonMarketCdfCdf";
module Guesstimator = {
[@bs.deriving abstract]
type discrete = {
xs: array(float),
ys: array(float),
};
let jsToDistDiscrete = (d: discrete): Types.DiscreteDistribution.t => {
xs: xsGet(d),
ys: ysGet(d),
};
[@bs.deriving abstract]
type combined = {
continuous: distJs,
discrete,
};
let toContinous = (r: combined) => continuousGet(r) |> jsToDist;
let toDiscrete = (r: combined): Types.DiscreteDistribution.t =>
discreteGet(r) |> jsToDistDiscrete;
let toMixed = (r: combined): Types.MixedDistribution.t => {
discrete: toDiscrete(r),
continuous: toContinous(r),
};
[@bs.module "./GuesstimatorLibrary.js"]
external toGuesstimator: (string, int) => distJs = "run";
external toGuesstimator: (string, int) => combined = "run";
};
};
module Distribution = {
@ -49,7 +76,8 @@ module Distribution = {
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);
let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x);
let fromString = (str: string, sampleCount: int) =>
JS.toGuesstimator(str, sampleCount) |> JS.jsToDist;
JS.Guesstimator.toGuesstimator(str, sampleCount)
|> JS.Guesstimator.toMixed;
let integral = dist => dist |> JS.distToJs |> JS.integral;
let differentialEntropy = (maxCalculationLength, dist) =>
dist

View File

@ -33,14 +33,19 @@ const ratioSize = samples => {
return minMaxRatio(minValue, maxValue);
};
const toPdf = (values, sampleCount, min, max) => {
const samples = new Samples(values);
let duplicateSamples = _(values).groupBy().pickBy(x => x.length > 1).keys().value();
let totalLength = _.size(values);
let frequencies = duplicateSamples.map(s => ({value: parseFloat(s), percentage: totalLength/_(values).filter(x => x ==s).size()}));
let continuousSamples = _.difference(values, frequencies.map(f => f.value));
const samples = new Samples(continuousSamples);
const ratioSize$ = ratioSize(samples);
const width = ratioSize$ === 'SMALL' ? 20 : 1;
const cdf = samples.toCdf({ size: sampleCount, width, min, max });
return {ys:cdf.ys, xs:cdf.xs};
return {continuous:{ys:cdf.ys, xs:cdf.xs}, discrete: {xs: frequencies.map(f => f.value), ys: frequencies.map(f => f.percentage)}};
};
let run = (text, sampleCount, inputs=[], min=false, max=false) => {