I'm trying to fit an Akima Spline curve in C# using the same method as this tool: https://www.mycurvefit.com/share/4ab90a5f-af5e-435e-9ce4-652c95c3d9a7
This curve gives me the exact shape I'm after (the curve line peaking at X = 30M, the highest point from the sample data)
But when I use MathNet's Akima function, and plot 52 points from the same data set:
var x = new List<double> { 0, 15000000, 30000000, 40000000, 60000000 };
var y = new List<double> { 0, 93279805, 108560423, 105689254, 90130257 };
var curveY = new List<double>();
var interpolation = MathNet.Numerics.Interpolation.CubicSpline.InterpolateAkima(x.ToArray(), y.ToArray());
for (int i=1; i<=52; i++)
{
var cY = interpolation.Interpolate((60000000/52)*i);
curveY.Add(cY);
}
I don't get the same curve at all, I get a curve which peaks around X = 26M, and looks much more like a Natural Spline: https://www.mycurvefit.com/share/faec5545-abf1-4768-b180-3e615dc60e3a
What is the reason the Akimas look so different? (especially in terms of peak)
Interpolate method waiting double parameter but this is integer (60000000 / 52) * i
change (60000000 / 52) * i to (60000000d / 52d) * i
I gave up with the MathNet functions and used the CubicSpline.FitParametric() function on this implementation instead: https://www.codeproject.com/Articles/560163/Csharp-Cubic-Spline-Interpolation
This successfully gave me the desired fit I was after (which fully respects the sample data peak).
Related
I've tried several combinations of Mathdotnet's LogNormal and Normal classes: https://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/LogNormal.
I seem to get a lot closer to the result I'm looking for using the mean and standard deviation as parameters. However, I notice that when I use larger numbers, like numberOfMinutes my results do not deviate past the mean like they do with smaller numbers like numberOfDays do. I know I'm not thinking about this right and could use some help.
Also, I'd like to use the geometric mean vs the mean but I didn't know what parameter to use for the variance given I couldn't pinpoint how to even use it for the mean.
Finally, I hope the answer to this also answers the same issue I'm having with the Normal distribution.
List<double> numberOfDays = new List<double> { 10, 12, 18, 30 };
double mean = numberOfDays.Mean(); // 17.5
double geometricMean = numberOfDays.GeometricMean(); // 15.954
double variance = numberOfDays.Variance(); // 81
double standardDeviation = numberOfDays.StandardDeviation(); // 9
// Do I need a Geometric Standard Deviation or Variance
double numberOfDaysSampleMV = LogNormal.WithMeanVariance(mean, variance).Sample(); // One example sample yielded 40.23
double numberOfDaysSampleMSD = LogNormal.WithMeanVariance(mean, standardDeviation).Sample(); // One example sample yielded 17.33
I believe you are confused about the parameters required. Using conventional notation, you have set X which you believe is LogNormal:
X = { 10, 12, 18, 30 }
mean: m = 17.5
standard deviation: sd = 9
from this you derive set Y which is Normal:
Y = {2.30,2.48,2.89,3.4}
mean: mu = 2.77
standard deviation: sigma = 0.487
Note that mu and sigma are computed from Y, not X. To create sample of the LogNormal data, you use mu and sigma, not m and sd.
double[] sample = new double[100];
LogNormal.Samples(sample, mu, sigma);
This is consistent with the Wikipedia article on the LogNormal distribution. The Numerics documentation is not clear.
Here is my test program which might be useful:
List<double> X = new List<double> { 10, 12, 18, 30 }; // assume to be LogNormal
double m = X.Mean(); // mean of log normal values = 17.5
double sd = X.StandardDeviation(); // standard deviation of log normal values = 9
List<double> Y = new List<double> { };
for (int i = 0; i < 4; i++)
{
Y.Add(Math.Log(X[i]));
}
// Y = {2.30,2.48,2.89,3.4}
double mu = Y.Mean(); // mean of normal values = 2.77
double sigma = Y.StandardDeviation(); // standard deviation of normal values = 0.487
double[] sample = new double[100];
LogNormal.Samples(sample, mu, sigma); // get sample
double sample_m = sample.Mean(); // 17.93, approximates m
double sample_sd = sample.StandardDeviation(); // 8.98, approximates sd
sample = new double[100];
Normal.Samples(sample, mu, sigma); // get sample
double sample_mu = sample.Mean(); //2.77, approximates mu
double sample_sigma = sample.StandardDeviation(); //0.517 approximates sigma
Using your test program above my samples came out like this.
Using LogNormal(mu, sigma)
I'm ultimately concerned about the values greater than 30 and less than 10.
However, by trail and error [accidentally], when I use the following method to get the samples using the original m and sd variable in your test program I get the results I'm looking for. I do not want to go forward with something I accidentally did.
sample = new double[100];
for (int i = 0; i < 100; i++)
{
sample[i] = LogNormal.WithMeanVariance(m, sd).Sample();
}
Using LogNormal.WithMeanVariance(m, sd)
My values are consistently between the Min and Max and concentrated around the Mean.
My example shows pretty clearly how to get a LogNormal sample that has the mean and standard deviation of the original data.
The min/max of 10/30 is unrealistic if you are going create your samples based on the mean and standard deviation of the sample. Suppose you took of random sample of the weights of 4 people out of a population of 1000 people. Would you expect your sample to include both the lightest and heaviest of the population?
LogNormal.WithMeanVariance(m, sd) is wrong. The units are wrong. It's expecting a variance would have the units of ln(days)^2 while sd has units of days.
I suggest you a) use LogNormal(mu,sigma) and discard any values that are outside your min/max range or b) use LogNormal(mu,c*sigma) for some value of c less than one to reduce the variance enough that all the values are in your min/max range. The choice depends on the nature of your project.
The Wikipedia entry on the LogNormal distribution has formulas for computing mu and sigma from m and sd which might be better than calculating from the Y data.
I'm trying to use MathNet to calculate weighted linear regression of my data.
The documentation is here.
I'm trying to find a x + b = y such that it would best fit a list of (x,y,w), where w is weight of each point.
var r = WeightedRegression.Weighted(
weightedPoints.Select(p=>new Tuple<double[],double>(new [] { p.LogAvgAmount}, p.Frequency),
weightedPoints.Select(p=>Convert.ToDouble(p.Weight)).ToArray(), false);
As result, in r I'm getting a single point. What I'm expecting is values of a and b.
What am I doing wrong?
WeightedRegression.Weighted expects a predictor matrix as the first parameter, and only the LogAvgAmount is being passed. Try adding a 1 to the list or invoking WeightedRegression.Weighted with intercept: true
var x = weightedPoints.Select(p => new[] {p.LogAvgAmount}).ToArray();
var y = weightedPoints.Select(p => p.Frequency).ToArray();
var w = weightedPoints.Select(p => Convert.ToDouble(p.Weight)).ToArray();
// r1 == r2
var r1 = WeightedRegression.Weighted(weightedPoints.Select(p =>
new[] {1, p.LogAvgAmount}).ToArray(), y, w);
var r2 = WeightedRegression.Weighted(x, y, w, intercept: true);
Using Math.Net Numerics might be a good idea.
Weighted Regression
Sometimes the regression error can be reduced by dampening specific data points. We can achieve this by introducing a weight matrix W into the normal equations XTy=XTXp. Such weight matrices are often diagonal, with a separate weight for each data point on the diagonal.
var p = WeightedRegression.Weighted(X,y,W);
Weighter regression becomes interesting if we can adapt them to the point of interest and e.g. dampen all data points far away. Unfortunately this way the model parameters are dependent on the point of interest t.
1: // warning: preliminary api
2: var p = WeightedRegression.Local(X,y,t,radius,kernel);
You can find more info at:
https://numerics.mathdotnet.com/regression.html
I'm performing simple linear regression with Math.NET.
I provided a common code sample below. Alternative to this example one can use the Fit class for simple linear regression.
What I additionally want is to specify additional constraints like a fixed y-intercept or force the fit to run throug a fixed point, e.g. (2, 2). How to achieve this in Math.NET?
var xdata = new double[] { 10, 20, 30 };
var ydata = new double[] { 15, 20, 25 };
var X = DenseMatrix.CreateFromColumns(new[] {new DenseVector(xdata.Length, 1), new DenseVector(xdata)});
var y = new DenseVector(ydata);
var p = X.QR().Solve(y);
var a = p[0];
var b = p[1];
You can modify your data set to reflect the constraint , and then use the standard math.Net linear regression
if (x0,y0) is the point through which the regression line must pass,
fit the model y−y0=β(x−x0)+ε, i.e., a linear regression with "no
intercept" on a translated data set.
see here : https://stats.stackexchange.com/questions/12484/constrained-linear-regression-through-a-specified-point
and here : http://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)#Constrained_linear_least_squares
First of all, it you want to force the regression through the origin, you can use LineThroughOrigin or alternativelly LineThroughOriginFunc if what you want is the function itself.
To force the regression to have a desired intercept, I would perform a normal linear regression and get the intercept and slope (knowing these you know everything about your linear function).
With this information, you can compensate the intercept, for example:
If you made your regression in which
intercept = 2
slope = 1
Then you know that your equation would be y = x + 2.
If you want the same function to cross the y axis in 3 (y = x + 3), you would just need to add 1 to the intercept so that
intercept = 3
slope = 1
I have recently used Visual Basic .Net to write a particle system which emits particles with random velocities in the x and y direction and is affected by gravity. I switched to C# .Net and used the XNA Game Studio which makes the graphics handling much more convenient than GDI+.
The problem I have with C# is that the random numbers are not "random enough". My particle system has 2500 particles but you can clearly see that the particles are distributed in a grid-like fashion about 100 pixels apart and I did not have that problem with Visual Basic's Rnd() function.
What does Visual Basic do which C# does not, and how can I get the same results in C#?
I have tried to re-initialise my random numbers at different stages of the game loop but I end up either with my particles staying at one position or emitting just in a constant stream in one direction.
This is my C# code: LoadContent is called first thing after the program has started. I'm using the millisecond as a seed just so that I start each time with a different configuration.
The next time I re-seed is after all the calculations are done on the system just before rendering. The other alternative I tried is to re-seed after every 100 particles have been calculated but with no difference.
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
mousePos = Content.Load<Texture2D>("Point");
spriteTex = Content.Load<Texture2D >("Point");
rnd = new Random(a.Millisecond);
for (int i = 0; i < spritePos .Length; i++)
{
newPos[i] = new Vector2(800, 450);
spritePos[i] = newPos[i] ;
Scale[i] = rnd.Next(100,500);
renderCol[i] = new Color(rnd.Next(255), rnd.Next(255), rnd.Next(255), 1);
spriteVelocity[i] = new Vector2((rnd.Next(2000)-1000)/100, -rnd.Next(500,1500)/100);
Life[i] = rnd.Next(60);
Rotate[i] = (rnd.Next(1000)-500) * 0.001f;
RotateSpeed[i] = (rnd.Next(1000)-500) * 0.0001f;
}
}
This is my VB code, the only place where I use the rnd function:
For i = x To x + 1000
ptc(i) = New particle(New Vector((Rnd() * 200) - 200 * Rnd(), Rnd() * -100 - 200 * Rnd() - 200), New Vector(e.X, e.Y), 500, Color.FromArgb(Rnd() * 255, 255, 0))
x += 1
Next
In my VB code there is no place where I call the randomize function, I have noticed that my particles have the same pattern-like behaviour if I do. Excuse all the strange arithmetic, it's all just experimentation.
Ok, what you do to fix it Charl, is to create a single Random object (which you are) with no seed, and use it over and over again. So something like:
const double max = 1000.0;
Random rand = new Random(); // Like mentioned, don't provide a seed, .NET already picks a great seed for you
for(int iParticle = 0; iParticle < 2500; iParticle++)
{
double x = rand.NextDouble() * max; // Will generate a random number between 0 and max
double y = rand.NextDouble() * max;
}
To get a random floating point value (float or double) between a lower and upper bound, you can use something like:
double x = (rand.NextDouble() * (max - min)) + min;
EDIT: And make sure to use double or float. Ints are whole numbers only, doubles and floats can store real numbers and is probably what VB was using.
If you had posted some code we would probably have been able to point out where you are creating a new Random() object for each call .
Like in, for example, Random number in a loop
After seeing the code,
are you aware that (rnd.Next(2000)-1000)/100 is an integer only expression? The result will be converted to float but always end in ##.0.
In VB I / J yields a double.
Random class ensures pseudo-randomness, if that is what you are using. Have a look at RNGCryptoServiceProvider.
I have problem in dynamic memory allocation getting data from matrix
Image image_gray = new Image("im1.jpg");
Matrix circles = new Matrix(100, 1, 3);
Question 1: How can I locate dynamic memory because I don't know the number of circles?
Emgu.CV.CvInvoke.cvHoughCircles(image_gray, circles, HOUGH_TYPE.CV_HOUGH_GRADIENT,
2, 100, 200, 100, 10, 500);
Question 2: Now circle is matrix with [100 ,3], How can I get
point center= Round (circle[i][1], circle[i][1])
How can I get
int radius= circle[i][2];
what should my for loop look like to get data from matrix and casting should be point and int.
I tried already (NOT WORKING / ERROR)
for (int i=0; i < circles.Rows; i++)
{ Matrix entry = circles.GetRow(i);
float x = entry[0];
float y = entry[1];
float r = entry[2];} // NOT WORKING
because instead of copying (required) only (i) row it copies whole matrix( circles) and float x=......gives errors
No overload for method 'this' takes '1' arguments
please help me in this regard
regards
sorry to answer my question. please give some hint to dynamic memory allocation and matrix data
The documentation suggests that it will grow the matrix to fit, but it also contradicts that, so honestly, I would try a 1 row 1 col matrix on an image with more circles and see what it gives you. I see that you're using Matrix type - I don't know how you convert to the IntPtr needed by cvHoughCircles, but it should be straight forward to iterate over each row and pull out the results, which are 3 floats: (x, y, r) -
for (int i=0; i < circles.Cols; i++) {
Matrix<float> entry = circles.GetRow(i);
float x = entry[0]; // guessing here - the doc'n is truly awful
float y = entry[1];
float r = entry[2];
}