# 《Practical WPF Charts and Graphics 》翻译——之11章 曲线拟合（2）

public delegate doubleModelFunction(double x);
public static VectorRLinearRegression(double[] xarray, double[] yarray,
ModelFunction[] f, out double sigma)
{
int m = f.Length;
MatrixR A = new MatrixR(m, m);
VectorR b = new VectorR(m);
int n = xarray.Length;

for (int k = 0; k < m; k++)
{
b[k] = 0.0;
for (int i = 0; i < n; i++)
{
b[k] += f[k](xarray[i]) *yarray[i];
}
}

for (int j = 0; j < m; j++)
{
for (int k = 0; k < m; k++)
{
A[j, k] = 0.0;
for (int i = 0; i < n; i++)
{
A[j, k] += f[j](xarray[i]) *f[k](xarray[i]);
}
}
}
VectorR coef = GaussJordan(A, b);

// Calculate the standard deviation:
double s = 0.0;
for (int i = 0; i < n; i++)
{
double s1 = 0.0;
for (int j = 0; j < m; j++)
{
s1 += coef[j] * f[j](xarray[i]);
}
s += (yarray[i] - s1) * (yarray[i] -s1);
}
sigma = Math.Sqrt(s / (n - m));
return coef;
}

在LinearRegression方法里，我们指定系数矩阵A和向量b。我们接着通过GaussJordan方法求解标准方程.根据解决方案,我们计算了标准差.这个方法返回多项式(一个VectorR的对象)的系数;我们在PolynomialFit方法里使用out前缀指定标准差。

public static VectorRLinearRegression(double[] xarray, double[] yarray,
ModelFunction[] f, outdouble sigma)
{

}

<Windowx:Class="CurveFitting.PolynomialFit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:chart="clr-namespace:LineChartControl;assembly=LineChartControl"
Title="PolynomialFit"Height="450" Width="500">
<Grid x:Name="rootGrid"SizeChanged="rootGrid_SizeChanged">
<chart:LineChartControlLibx:Name="myChart" Xmin="0" Xmax="6"XTick="1"
Ymin="-100"Ymax="600" YTick="100" Title="PolynomialFitting"/>
</Grid>
</Window>

using System;
usingSystem.Windows;
usingSystem.Windows.Controls;
usingSystem.Windows.Media;

namespaceCurveFitting
{
public partial class PolynomialFit : Window
{
public PolynomialFit()
{
InitializeComponent();
}
private voidrootGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
myChart.Width =rootGrid.ActualWidth;
myChart.Height =rootGrid.ActualHeight;
}

{
double[] x0 = new double[] { 1, 2,3, 4, 5 };
double[] y0 = new double[] { 5.5,43.1, 128, 290.7, 498.4 };

VectorR[] results = new VectorR[3];

for (int i = 0; i <results.Length; i++)
{
double sigma = 0;
results[i] =CurveFittingAlgorithms.PolynomialFit(x0, y0,
i + 1, out sigma);
}

// Plot results:
myChart.DataCollection.DataList.Clear();
LineCharts.DataSeries ds;
// Plot results:
myChart.DataCollection.DataList.Clear();
LineCharts.DataSeries ds;
// Plot original data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.Transparent;
ds.SeriesName ="Original";
ds.Symbols.SymbolType =LineCharts.Symbols.SymbolTypeEnum.Triangle;
ds.Symbols.BorderColor =Brushes.Black;
for (int i = 0; i < x0.Length;i++)
{
}
// 1st order fitting data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.DarkGreen;
ds.LineThickness = 2;
ds.SeriesName = "1st OrderFitting";
for (int i = 0; i < 141; i++)
{
double x = -1.0 + i / 20.0;
double y = results[0][0] +results[0][1] * x;
}
// 2nd order fitting data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.Red;
ds.LineThickness = 2;
ds.LinePattern = LineCharts.DataSeries.LinePatternEnum.Dash;
ds.SeriesName = "2nd OrderFitting";
for (int i = 0; i < 141; i++)
{
double x = -1.0 + i / 20.0;
double y = results[1][0] +results[1][1] * x +
results[1][2] * x * x;
}

// 3rd order fitting data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.DarkBlue;
ds.LineThickness = 2;
ds.LinePattern =LineCharts.DataSeries.LinePatternEnum.DashDot;
ds.SeriesName = "3rd OrderFitting";
for (int i = 0; i < 141; i++)
{
double x = -1.0 + i / 20.0;
double y = results[2][0] +results[2][1] * x +
results[2][2] * x *x + results[2][3] * x * x * x;
}
myChart.IsLegend = true;
myChart.LegendPosition =LineCharts.Legend.LegendPositionEnum.NorthWest;
}
}
}

对于最简单的线性回归，例如，直线拟合，它的拟合函数通过f(x)=a+bx给出，前面的方程就变成

public static double[]WeightedLinearRegression(double[] xarray, double[] yarray, double[] warray)
{
int n = xarray.Length;
double xw = 0.0;
double yw = 0.0;
double b1 = 0.0;
double b2 = 0.0;
double a = 0.0;
double b = 0.0;

for (int i = 0; i < n; i++)
{
xw += xarray[i] / n;
yw += yarray[i] / n;
}
for (int i = 0; i < n; i++)
{
b1 += warray[i] * warray[i] * yarray[i]* (xarray[i] - xw);
b2 += warray[i] * warray[i] * xarray[i]* (xarray[i] - xw);
}
b = b1 / b2;
a = yw - xw * b;
return new double[] { a, b };
}

注意到数据对数的最小二乘拟合与原始数据的最小二乘拟合不太一样。对数拟合的残差是

加上我们有下面的一组数据：

x = 1, 2 , 3, 4, 5 , 6, 7,8, 9, 10

y = 1.9398, 2.9836,5.9890, 10.2, 20.7414, 23.232, 69.5855, 82.5836, 98.1779 ,339.3256

添加一个新的WPF Windows应用程序到当前项目中，命名为WeightedLinearRegression.下面是这个例子的XAML文件：

<Windowx:Class="CurveFitting.WeightedLinearRegression"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:chart="clr-namespace:LineChartControl;assembly=LineChartControl"
Title="WeightedLinearRegression"Height="320" Width="600">
<Grid x:Name="rootGrid"SizeChanged="rootGrid_SizeChanged">
<StackPanelOrientation="Horizontal">
<chart:LineChartControlLibx:Name="logChart"
Xmin="0"Xmax="11" XTick="1" Title="Log Scale Plot"/>
<chart:LineChartControlLibx:Name="linearChart"
Xmin="0"Xmax="11" XTick="1" Title="Linear ScalePlot"/>
</StackPanel>
</Grid>
</Window>

using System;
using System.Windows;
usingSystem.Windows.Controls;
usingSystem.Windows.Media;

namespace CurveFitting
{
public partial classWeightedLinearRegression : Window
{
public WeightedLinearRegression()
{
InitializeComponent();
}

private voidrootGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
logChart.Width =rootGrid.ActualWidth / 2;
logChart.Height =rootGrid.ActualHeight;
linearChart.Width =rootGrid.ActualWidth / 2;
linearChart.Height =rootGrid.ActualHeight;
}
{
double[] x0 = new double[] { 1, 2,3, 4, 5, 6, 7, 8, 9, 10 };
double[] y0 = new double[] {1.9398, 2.9836, 5.9890, 10.2, 20.7414,
23.232, 69.5855, 82.5836,98.1779, 339.3256 };
double[] ylog = new double[] {0.6626, 1.0931, 1.7899, 2.3224,
3.0321, 3.1455, 4.2426, 4.4138,4.5868, 5.8270 };

double[] results =
CurveFittingAlgorithms.WeightedLinearRegression(x0, ylog, y0);

// Plot linear scale results:
LinearScale(x0, y0, results);

// Plot log scale results:
LogScale(x0, ylog, results);
}
private void LinearScale(double[] x0,double[] y0, double[] results)
{
linearChart.DataCollection.DataList.Clear();
LineCharts.DataSeries ds;
linearChart.ChartStyle.Ymin = -50;
linearChart.ChartStyle.Ymax = 350;
linearChart.ChartStyle.YTick = 50;
linearChart.ChartStyle.YLabel ="Y";
// Plot original data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.Transparent;
ds.SeriesName = "Original";
ds.Symbols.SymbolType =LineCharts.Symbols.SymbolTypeEnum.Triangle;
ds.Symbols.BorderColor =Brushes.Black;
for (int i = 0; i < x0.Length; i++)
{
}
// Plot curve fittin data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.DarkGreen;
ds.LineThickness = 2;
ds.SeriesName = "CurveFitting";
for (int i = 0; i < 111; i++)
{
double x = 0.1 + i / 10.0;
double y = Math.Exp(results[0] +results[1] * x);
}
linearChart.Legend.IsLegend = true;
linearChart.Legend.LegendPosition =
LineCharts.Legend.LegendPositionEnum.NorthWest;
}
private void LogScale(double[] x0, double[]ylog, double[] results)
{
logChart.DataCollection.DataList.Clear();
LineCharts.DataSeries ds;
logChart.ChartStyle.Ymin = 0;
logChart.ChartStyle.Ymax = 7;
logChart.ChartStyle.YTick = 1;
logChart.ChartStyle.YLabel ="Log(y)";
// Plot original data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.Transparent;
ds.SeriesName ="Original";
ds.Symbols.SymbolType = LineCharts.Symbols.SymbolTypeEnum.Triangle;
ds.Symbols.BorderColor =Brushes.Black;
for (int i = 0; i < x0.Length;i++)
{
}

// Plot curve fittin data:
ds = new LineCharts.DataSeries();
ds.LineColor = Brushes.DarkGreen;
ds.LineThickness = 2;
ds.SeriesName = "CurveFitting";
for (int i = 0; i < 111; i++)
{
double x = 0.1 + i / 10.0;
double y = results[0] +results[1] * x;
}
logChart.Legend.IsLegend = true;
logChart.Legend.LegendPosition =
LineCharts.Legend.LegendPositionEnum.NorthWest;
}
}
}

double[] results =CurveFittingAlgorithms.WeightedLinearRegression(x0, ylog, y0);

我们可以通过将它们绘制出来来检验拟合结果的好坏（如图11-4）.你可以从图11-4中看到加权线性回归确实给出了一个很好的拟合结果。

08-16

04-13 1万+
12-31 1万+
08-08 1万+
06-05 49
07-09 53
03-18 1万+
05-05 9330
03-20 4184
09-05 2668
07-17 1462