Skip to content

Commit ff30fd2

Browse files
committed
Added an option to bound the Kernel Density by the data limits. Improved the solver methods in the Pert Percentile and PercentileZ classes. Improved the ToXElement() and FromXElement() methods in the Pert Percentile, PercentileZ, and Mixture distribution classes. Added a weighted Distance method to the Tools class. Added some additional functionality to the k-NN class.
1 parent 6660e4e commit ff30fd2

16 files changed

Lines changed: 691 additions & 40 deletions

File tree

4.8.1/Numerics/Distributions/Univariate/Base/UnivariateDistributionFactory.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ public static UnivariateDistributionBase CreateDistribution(UnivariateDistributi
172172
{
173173
distribution = new PertPercentileZ();
174174
}
175-
//else if (distributionType == UnivariateDistributionType.Poisson)
176-
//{
177-
// distribution = new Poisson();
178-
//}
175+
else if (distributionType == UnivariateDistributionType.Poisson)
176+
{
177+
distribution = new Poisson();
178+
}
179179
else if (distributionType == UnivariateDistributionType.Rayleigh)
180180
{
181181
distribution = new Rayleigh();
@@ -228,6 +228,16 @@ public static UnivariateDistributionBase CreateDistribution(XElement xElement)
228228
dist = Mixture.FromXElement(xElement);
229229
return dist;
230230
}
231+
else if (type == UnivariateDistributionType.PertPercentile)
232+
{
233+
dist = PertPercentile.FromXElement(xElement);
234+
return dist;
235+
}
236+
else if (type == UnivariateDistributionType.PertPercentileZ)
237+
{
238+
dist = PertPercentileZ.FromXElement(xElement);
239+
return dist;
240+
}
231241
else
232242
{
233243
dist = CreateDistribution(type);

4.8.1/Numerics/Distributions/Univariate/KernelDensity.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ public int SampleSize
211211
/// </summary>
212212
public Transform ProbabilityTransform { get; set; } = Transform.NormalZ;
213213

214+
/// <summary>
215+
/// Determines whether to use the data to set the minimum or maximum limits. If false, the limits are the data min and max +- 3 * Bandwidth, respectively.
216+
/// </summary>
217+
public bool BoundedByData { get; set; } = true;
218+
214219
/// <inheritdoc/>
215220
public override int NumberOfParameters
216221
{
@@ -341,7 +346,7 @@ public override double Minimum
341346
{
342347
if (_sampleData is null) return double.NaN;
343348
if (_sampleData.Count() == 0) return double.NaN;
344-
return Tools.Min(SampleData) - 3 * Bandwidth;
349+
return BoundedByData ? Tools.Min(SampleData) : Tools.Min(SampleData) - 3 * Bandwidth;
345350
}
346351
}
347352

@@ -352,7 +357,7 @@ public override double Maximum
352357
{
353358
if (_sampleData is null) return double.NaN;
354359
if (_sampleData.Count() == 0) return double.NaN;
355-
return Tools.Max(SampleData) + 3 * Bandwidth;
360+
return BoundedByData ? Tools.Max(SampleData) : Tools.Max(SampleData) + 3 * Bandwidth;
356361
}
357362
}
358363

@@ -510,6 +515,7 @@ public override double CDF(double x)
510515
{
511516
if (x < Minimum) return 0.0;
512517
if (x > Maximum) return 1.0;
518+
if (Minimum == Maximum) return double.NaN;
513519
if (!_cdfCreated) CreateCDF();
514520
return opd.GetYFromX(x, XTransform, ProbabilityTransform);
515521
}
@@ -522,21 +528,23 @@ public override double InverseCDF(double probability)
522528
throw new ArgumentOutOfRangeException("probability", "Probability must be between 0 and 1.");
523529
if (probability == 0.0) return Minimum;
524530
if (probability == 1.0) return Maximum;
531+
if (Minimum == Maximum) return double.NaN;
525532
if (!_cdfCreated) CreateCDF();
526533
return opd.GetXFromY(probability, XTransform, ProbabilityTransform);
527534
}
528535

529536
/// <inheritdoc/>
530537
public override UnivariateDistributionBase Clone()
531538
{
532-
return new KernelDensity(SampleData, KernelDistribution, Bandwidth);
539+
return new KernelDensity(SampleData, KernelDistribution, Bandwidth) { XTransform = XTransform, ProbabilityTransform = ProbabilityTransform, BoundedByData = BoundedByData };
533540
}
534541

535542
/// <summary>
536543
/// Create the empirical CDF.
537544
/// </summary>
538545
private void CreateCDF()
539546
{
547+
540548
// Create wide bins
541549
int n = 1000;
542550
var bins = Stratify.XValues(new StratificationOptions(Minimum, Maximum, n));

4.8.1/Numerics/Distributions/Univariate/Mixture.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
using Numerics.Sampling;
3535
using System;
3636
using System.Collections.Generic;
37+
using System.Globalization;
3738
using System.Linq;
3839
using System.Xml.Linq;
3940

@@ -1046,12 +1047,26 @@ public override XElement ToXElement()
10461047
var result = new XElement("Distribution");
10471048
result.SetAttributeValue(nameof(Type), Type.ToString());
10481049
result.SetAttributeValue(nameof(IsZeroInflated), IsZeroInflated.ToString());
1049-
result.SetAttributeValue(nameof(ZeroWeight), ZeroWeight.ToString());
1050+
result.SetAttributeValue(nameof(ZeroWeight), ZeroWeight.ToString("G17", CultureInfo.InvariantCulture));
10501051
result.SetAttributeValue(nameof(XTransform), XTransform.ToString());
10511052
result.SetAttributeValue(nameof(ProbabilityTransform), ProbabilityTransform.ToString());
1052-
result.SetAttributeValue(nameof(Weights), String.Join("|", Weights));
10531053
result.SetAttributeValue(nameof(Distributions), String.Join("|", Distributions.Select(x => x.Type)));
1054-
result.SetAttributeValue("Parameters", String.Join("|", GetParameters));
1054+
// Weights
1055+
var weights = Weights;
1056+
var weightStrings = new string[NumberOfParameters];
1057+
for (int i = 0; i < NumberOfParameters; i++)
1058+
{
1059+
weightStrings[i] = weights[i].ToString("G17", CultureInfo.InvariantCulture);
1060+
}
1061+
result.SetAttributeValue(nameof(Weights), String.Join("|", weightStrings));
1062+
// Parameters
1063+
var parms = GetParameters;
1064+
var parmStrings = new string[NumberOfParameters];
1065+
for (int i = 0; i < NumberOfParameters; i++)
1066+
{
1067+
parmStrings[i] = parms[i].ToString("G17", CultureInfo.InvariantCulture);
1068+
}
1069+
result.SetAttributeValue("Parameters", String.Join("|", parmStrings));
10551070
return result;
10561071
}
10571072

@@ -1077,7 +1092,7 @@ public static Mixture FromXElement(XElement xElement)
10771092
var w = xElement.Attribute(nameof(Weights)).Value.Split('|');
10781093
for (int i = 0; i < w.Length; i++)
10791094
{
1080-
double.TryParse(w[i], out var weight);
1095+
double.TryParse(w[i], NumberStyles.Any, CultureInfo.InvariantCulture, out var weight);
10811096
weights.Add(weight);
10821097
}
10831098
}
@@ -1099,7 +1114,7 @@ public static Mixture FromXElement(XElement xElement)
10991114
}
11001115
if (xElement.Attribute(nameof(ZeroWeight)) != null)
11011116
{
1102-
double.TryParse(xElement.Attribute(nameof(ZeroWeight)).Value, out var zeroWeight);
1117+
double.TryParse(xElement.Attribute(nameof(ZeroWeight)).Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var zeroWeight);
11031118
mixture.ZeroWeight = zeroWeight;
11041119
}
11051120
if (xElement.Attribute(nameof(XTransform)) != null)
@@ -1118,7 +1133,7 @@ public static Mixture FromXElement(XElement xElement)
11181133
var parameters = new List<double>();
11191134
for (int i = 0; i < vals.Length; i++)
11201135
{
1121-
double.TryParse(vals[i], out var parm);
1136+
double.TryParse(vals[i], NumberStyles.Any, CultureInfo.InvariantCulture, out var parm);
11221137
parameters.Add(parm);
11231138
}
11241139
mixture.SetParameters(parameters);

4.8.1/Numerics/Distributions/Univariate/PertPercentile.cs

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030

3131
using System;
3232
using System.Collections.Generic;
33+
using System.Globalization;
3334
using System.Reflection;
35+
using System.Xml.Linq;
3436
using Numerics.Mathematics.Optimization;
3537

3638
namespace Numerics.Distributions
@@ -383,9 +385,11 @@ double sse(double[] x)
383385

384386
}
385387

386-
var solver = new BFGS(sse, 3, Initials, Lowers, Uppers);
387-
solver.RelativeTolerance = 1E-4;
388+
var solver = new NelderMead(sse, 3, Initials, Lowers, Uppers);
389+
solver.MaxFunctionEvaluations = 200;
390+
solver.RelativeTolerance = 1E-8;
388391
solver.AbsoluteTolerance = 1E-8;
392+
solver.ComputeHessian = false;
389393
solver.ReportFailure = false;
390394
solver.Minimize();
391395
var solution = solver.BestParameterSet.Values;
@@ -470,6 +474,106 @@ public Pert ToPert()
470474
return new Pert(_beta.Min, _beta.Mode, _beta.Max);
471475
}
472476

477+
/// <inheritdoc/>
478+
public override XElement ToXElement()
479+
{
480+
var result = new XElement("Distribution");
481+
result.SetAttributeValue(nameof(Type), Type.ToString());
482+
result.SetAttributeValue("ParametersSolved", _parametersSolved.ToString());
483+
// Parameters
484+
var parms = GetParameters;
485+
var parmStrings = new string[NumberOfParameters];
486+
for (int i = 0; i < NumberOfParameters; i++)
487+
{
488+
parmStrings[i] = parms[i].ToString("G17", CultureInfo.InvariantCulture);
489+
}
490+
result.SetAttributeValue("Parameters", String.Join("|", parmStrings));
491+
// Beta Distribution parameters
492+
parms = _beta.GetParameters;
493+
parmStrings = new string[_beta.NumberOfParameters];
494+
for (int i = 0; i < _beta.NumberOfParameters; i++)
495+
{
496+
parmStrings[i] = parms[i].ToString("G17", CultureInfo.InvariantCulture);
497+
}
498+
result.SetAttributeValue("BetaParameters", String.Join("|", parmStrings));
499+
return result;
500+
}
501+
502+
/// <summary>
503+
/// Create a Pert-Percentile distribution from XElement.
504+
/// </summary>
505+
/// <param name="xElement">The XElement to deserialize.</param>
506+
/// <returns>A new mixture distribution.</returns>
507+
public static PertPercentile FromXElement(XElement xElement)
508+
{
509+
UnivariateDistributionType type = UnivariateDistributionType.Deterministic;
510+
if (xElement.Attribute(nameof(UnivariateDistributionBase.Type)) != null)
511+
{
512+
Enum.TryParse(xElement.Attribute(nameof(UnivariateDistributionBase.Type)).Value, out type);
513+
514+
}
515+
if (type == UnivariateDistributionType.PertPercentile)
516+
{
517+
bool parametersSolved = false;
518+
if (xElement.Attribute("ParametersSolved") != null)
519+
{
520+
bool.TryParse(xElement.Attribute("ParametersSolved").Value, out parametersSolved);
521+
}
522+
else
523+
{
524+
// This was saved from Base method
525+
var dist = new PertPercentile();
526+
var names = dist.GetParameterPropertyNames;
527+
var parms = dist.GetParameters;
528+
var vals = new double[dist.NumberOfParameters];
529+
for (int i = 0; i < dist.NumberOfParameters; i++)
530+
{
531+
if (xElement.Attribute(names[i]) != null)
532+
{
533+
double.TryParse(xElement.Attribute(names[i]).Value, NumberStyles.Any, CultureInfo.InvariantCulture, out vals[i]);
534+
}
535+
}
536+
dist.SetParameters(vals);
537+
return dist;
538+
539+
}
540+
541+
var beta = new GeneralizedBeta();
542+
if (xElement.Attribute("BetaParameters") != null)
543+
{
544+
var vals = xElement.Attribute("BetaParameters").Value.Split('|');
545+
var parameters = new List<double>();
546+
for (int i = 0; i < vals.Length; i++)
547+
{
548+
double.TryParse(vals[i], NumberStyles.Any, CultureInfo.InvariantCulture, out var parm);
549+
parameters.Add(parm);
550+
}
551+
beta.SetParameters(parameters);
552+
}
553+
double _5th = 0, _50th = 0, _95th = 0;
554+
if (xElement.Attribute("Parameters") != null)
555+
{
556+
var vals = xElement.Attribute("Parameters").Value.Split('|');
557+
double.TryParse(vals[0], NumberStyles.Any, CultureInfo.InvariantCulture, out _5th);
558+
double.TryParse(vals[1], NumberStyles.Any, CultureInfo.InvariantCulture, out _50th);
559+
double.TryParse(vals[2], NumberStyles.Any, CultureInfo.InvariantCulture, out _95th);
560+
}
561+
562+
var pert = new PertPercentile()
563+
{
564+
_parametersSolved = parametersSolved,
565+
_beta = beta,
566+
_5th = _5th,
567+
_50th = _50th,
568+
_95th = _95th };
569+
570+
return pert;
571+
}
572+
else
573+
{
574+
return null;
575+
}
576+
}
473577

474578
}
475579
}

0 commit comments

Comments
 (0)