!   Fit a discrete distribution to             (FitDiscDist.lng)
  a given target/theoretical distribution.
  Match the theoretical pdf with the discrete
  as closely as possible, subject to exactly matching
  the mean and SD;
! Keywords: Fit distribution, Distribution fit, Probability computation,
            Stochastic;
SETS:
 point : p, pt, errup, errdn;
 distset / N, G, T/; ! Names for target distributions supported;
 distn( distset);
ENDSETS
DATA: mu = 10; ! Target mean of discrete distn; sd = 3; ! Target SD (for Normal & Gamma); lo = 1; ! Lowest value in discrete distn; hi = 20; ! Highest value in discrete distn; distn = N; ! Choose a target from N(ormal), G(amma), or T(riangle); point = 1..30; ! Workspace; ENDDATA SUBMODEL fitdist: ! Choose the fitted probabilities p( i) to closely match the given target probabilities pt( i), and exactly match the target mu and target sd; ! Minimize the total error of fit; min = errtot; ! Match the mean; mu = @SUM( point( i) : i* p( i)); ! Match the sd; sd*sd = @SUM( point( i): p(i)*( i - mu)^2); ! Compute the relative errors in matching the theoretical pdf; @FOR( point( i): ( errup( i) - errdn( i))* pt( i) = p( i) - pt( i); ); ! Compute total sum of absolute relative errors; errtot = @SUM( point( i): errup( i) + errdn( i)); ENDSUBMODEL
procedure donormal: ! Generate a discretized version of the Normal, that may however not quite match the mean and SD; ! Take care of low bin; prev = @PNORMCDF( mu, sd, lo + 0.5); pt( lo) = prev; ! The interior bins; @FOR( point( i) | lo #lt# i #and# i #lt# hi: ptnu = @PNORMCDF( mu, sd, i + 0.5); pt( i) = ptnu - prev; prev = ptnu; ); ! Take care of high bin; pt( hi) = 1 - prev; ENDprocedure procedure dogamma: ! Generate a discretized version of the Gamma, that may however not quite match the mean and SD; ! We need shape*scale = mu; ! shape*scale^2 = sd^2; ! Solving ; scale = sd* sd/ mu; shape = mu/ scale; ! Take care of low bin; prev = @PGAMMCDF( scale, shape, lo + 0.5); pt( lo) = prev; ! The interior bins; @FOR( point( i) | lo #lt# i #and# i #lt# hi: ptnu = @PGAMMCDF( scale, shape, i + 0.5) ; pt( i) = ptnu - prev; prev = ptnu; ); ! Take care of high bin; pt( hi) = 1 - prev; ENDprocedure procedure dotriangular: ! Generate a triangular distribution in [lo, hi]; ! We need: lo + hi + mode = 3*mu, lo^2 + mode^2 + hi^2 - lo*mode - lo*hi - mode* hi = 18*sd*sd; ! Solving ; mode = 3*mu - lo - hi; sd = ((lo^2 + mode^2 + hi^2 - lo* mode - lo* hi - mode* hi)/18)^0.5; ! Take care of low bin; prev = @PTRIACDF( lo, hi, mode, lo + 0.5); pt( lo) = prev; ! The interior bins; @FOR( point( i) | lo #lt# i #and# i #lt# hi: ptnu = @PTRIACDF( lo, hi, mode, i + 0.5); pt( i) = ptnu - prev; prev = ptnu; ); ! Take care of high bin; pt( hi) = 1 - prev; ENDprocedure CALC: ! Generate the appropriate target distribution; @FOR( distn( d) | d #eq# 1: donormal); @FOR( distn( d) | d #eq# 2: dogamma); @FOR( distn( d) | d #eq# 3: dotriangular); ! Take low and high points out of the problem; @FOR( point( i) | i #lt# lo #or# i #gt# hi: p( i) = 0; pt( i) = 0; ); ! @gen( fitdist); @SOLVE( fitdist); @CHARTBAR( 'Fitting a discrete distribution', 'x-axis', 'Probability', 'Theoretical', pt, 'Fitted', p); ENDCALC