Подбор параметров или как описать кривую - C#
Формулировка задачи:
Добрый день!
Стоит задача найти уравнение кривой вида y=A+B*exp(-x/C) (3 параметра)
В моем распоряжении внушительный массив данных (в среднем около 150 000 точек) y и x (см. рис. 0)
У меня получилось выполнить эту задачу с помощью VBA и поиска решений excel (Solver) (см. рис. 1, оранжевая кривая построена по найденным параметрам, синяя - исходная), но есть больше НО
Эксель очень плохо работает с такими большими массивами, обработка ячеек ведется по нескольку минут.
Есть может быть готовый метод для c# в который включен алгоритм Solver'a или может есть какой-нибудь еще способ найти коэффициенты уравнения кривой по массиву (y,x)?
Заранее спасибо!
Решение задачи: «Подбор параметров или как описать кривую»
textual
Листинг программы
class Program
{
public static double[] LeastSquaresBestFitLine1(double[] x, double[] y)
{
//Calculates equation of best-fit line using short cuts
int n = x.Length;
double xMean = 0.0;
double yMean = 0.0;
double numeratorSum = 0.0;
double denominatorSum = 0.0;
double bestfitYintercept = 0.0;
double bestfitSlope = 0.0;
double sigma = 0.0;
double sumOfResidualsSquared = 0.0;
//Calculates the mean values for x and y arrays
for (int i = 0; i < n; i++)
{
xMean += x[i] / n;
yMean += y[i] / n;
}
//Calculates the numerator and denominator for best-fit slope
for (int i = 0; i < n; i++)
{
numeratorSum += y[i] * (x[i] - xMean);
denominatorSum += x[i] * (x[i] - xMean);
}
//Calculate the best-fit slope and y-intercept
bestfitSlope = numeratorSum / denominatorSum;
bestfitYintercept = yMean - xMean * bestfitSlope;
//Calculate the best-fit standard deviation
for (int i = 0; i < n; i++)
{
sumOfResidualsSquared += (y[i] - bestfitYintercept - bestfitSlope * x[i]) * (y[i] - bestfitYintercept - bestfitSlope * x[i]);
}
sigma = Math.Sqrt(sumOfResidualsSquared / (n - 2));
return new double[] { bestfitYintercept, bestfitSlope, sigma };
}
public static double[] LeastSquaresWeightedBestFitLine1(double[] x, double[] y, double[] w)
{
//Calculates equation of best-fit line using short cuts
int n = x.Length;
double wxMean = 0.0;
double wyMean = 0.0;
double wSum = 0.0;
double wnumeratorSum = 0.0;
double wdenominatorSum = 0.0;
double bestfitYintercept = 0.0;
double bestfitSlope = 0.0;
double sigma = 0.0;
double sumOfResidualsSquared = 0.0;
//Calculates the sum of the weights w[i]
for (int i = 0; i < n; i++)
{
wSum += w[i];
}
//Calculates the mean values for x and y arrays
for (int i = 0; i < n; i++)
{
wxMean += w[i] * x[i] / wSum;
wyMean += w[i] * y[i] / wSum;
}
//Calculates the numerator and denominator for best-fit slope
for (int i = 0; i < n; i++)
{
wnumeratorSum += w[i] * y[i] * (x[i] - wxMean);
wdenominatorSum += w[i] * x[i] * (x[i] - wxMean);
}
//Calculate the best-fit slope and y-intercept
bestfitSlope = wnumeratorSum / wdenominatorSum;
bestfitYintercept = wyMean - wxMean * bestfitSlope;
//Calculate the best-fit standard deviation
for (int i = 0; i < n; i++)
{
sumOfResidualsSquared += w[i] * (y[i] - bestfitYintercept - bestfitSlope * x[i]) * (y[i] - bestfitYintercept - bestfitSlope * x[i]);
}
sigma = Math.Sqrt(sumOfResidualsSquared / (n - 2));
return new double[] { bestfitYintercept, bestfitSlope, sigma };
}
static void Main(string[] args)
{
Console.WriteLine("Testing Exponential Fit");
Console.WriteLine(" Original equation: y = a e^{cx}");
Console.WriteLine("Linearized equation: ln(y) = cx + ln(a)");
Console.WriteLine("which is in the form: Y = mx + b for a straight line\n");
double[] x = new double[] { 1, 2, 3, 4, 5 };
double[] y = new double[] { 3.5, 6.2, 9.5, 15.3, 20.4 };
double[] logy = new double[] { 1.25276, 1.82455, 2.25129, 2.72785, 3.01553 };
double[] results = LeastSquaresBestFitLine1(x, logy);
Console.WriteLine("Results without weights, just (x,ln(y)): ");
Console.WriteLine("Best-fit y-intercept b = ln(a) = {0}", results[0]);
Console.WriteLine("Best-fit slope = m = c ={0}", results[1]);
Console.WriteLine("Best-fit sigma = {0}", results[2]);
Console.WriteLine("Equation for weighted best-fit exponential:");
Console.WriteLine("y = a e^(cx) = {0}exp({1}x)\n", Math.Exp(results[0]), results[1]);
double[] resultsWt = LeastSquaresWeightedBestFitLine1(x, logy, y);
Console.WriteLine("Results with weights w = y. Calc (x,ln(y),w)):");
Console.WriteLine("Best-fit y-intercept b = ln(a)= {0}", resultsWt[0]);
Console.WriteLine("Best-fit slope = m = c = {0}", resultsWt[1]);
Console.WriteLine("Best-fit sigma = {0}", resultsWt[2]);
Console.WriteLine("Equation for weighted best-fit exponential:");
Console.WriteLine("y = a e^(cx) = {0}exp({1}x)\n", Math.Exp(resultsWt[0]), resultsWt[1]);
Console.ReadLine();
}
}