数学不好的人就是郁闷啊。

前两天写的自动外理HPLC数据的程序当中有一段代码是用来计算标准曲线的斜率的。这东西简单啊,一元线性回归嘛,用最小二乘法,以前写过的。

void Min2Method(float &slope, float &intercept, double X[], double Y[], int nCount)
{
	double   SumX, SumY, SumXY, SumX2;
 
	SumX = 0;
	SumX2 = 0;
	for(int i=0; i<nCount; i++)
	{
		SumX += X[i];
		SumX2 += (X[i] * X[i]);
	}
 
	SumY = 0;
	for(int i=0; i<nCount; i++)
	{
		SumY += Y[i];
	}
 
	SumXY = 0;
	for(int i=0; i<nCount; i++)
	{
		SumXY += ( X[i] * Y[i]);
	}
 
  	intercept = ( (SumX2*SumY - SumX*SumXY) / (nCount*SumX2 - SumX * SumX));
  	slope = ( (nCount*SumXY - SumX*SumY) / (nCount*SumX2 - SumX * SumX));
}

可是,老板要求,标准曲线要过原点,也就是过零点的斜率。要把横轴截距设置为零。这下就又不会了。只好google research(因为手头没有书)。谁让咱统计学没学好呢。

经过一番学习,终于了重新找回了那么一点点感觉。首先还是搞清楚上面的代码是怎么来的吧。

设有一组输入变量:(x1, x2, … , xn)都对应的有一组输出变量:(y1,y2, … , yn),它们满足一次线性关系:

y = a + b * x

其中 yi = a + b * xi + εi ( i = 1, …, n); 这里的期望值E(ε)=0, 方差Var(ε)=σ2属随机误差。

最小二乘法是高斯发明的,找到一条直线, 确定a和b的值使偏差平方和 (Q = Σ[yi - (a+b * xi)]2) 最小,即它对a和b求偏导为零:

(∂Q/∂a)= -2Σ[yi - (a+b * xi)] = 0                  (1)

(∂Q/∂b)= -2Σ{xi * [yi - (a+b * xi)]} = 0      (2)

分别得解:

n * a + b * Σ(xi) = Σ(yi)                                    (3)

a * Σ(xi)+ b * Σ(xi2) = Σ(xiyi)                        (4)

得到a和b

b = Σ[(xi-Σ(xi)/n) * (yi-Σ(yi)/n)]/Σ[(xi-Σ(xi)/n)2];

a = [Σ(yi) - b * Σ(xi)] / n.

现在如果要求a为零,那就是说(1)式不成立,只需要求解(2)式就可以了。当a=0, (2)变化为:

(∂Q/∂b)= -2Σ[xi * (yi - b * xi)] = 0 (5)

解得:

b * Σ(xi2) = Σ(xiyi)
b = Σ(xiyi)/Σ(xi2)

于是上面的程序为了得到过原点的直线斜率就可以改写为:

void Min2Method(float &slope, float &R2, double X[], double Y[], int nCount)
{
	double   SumX, SumY, SumXY, SumX2, SumY2, SumSSE, SumSST;
 
	SumX = 0;
	SumX2 = 0;
	for(int i=0; i<nCount; i++)
	{
		SumX += X[i];
		SumX2 += (X[i] * X[i]);
	}
 
	SumY = 0;
	SumY2 = 0;
	for(int i=0; i<nCount; i++)
	{
		SumY += Y[i];
		SumY2 += (Y[i] * Y[i]);
	}
 
	SumXY = 0;
	for(int i=0; i<nCount; i++)
	{
		SumXY += ( X[i] * Y[i]);
	}
 
	slope = SumXY / SumX2;
 
	SumSSE = 0;
	double avgY = SumY/nCount;
	for(int i=0; i<nCount; i++)
	{
		SumSSE += (Y[i] - avgY)*(Y[i] - avgY);
		SumSST += (Y[i] - X[i]*slope)
			* (Y[i] - X[i]*slope);
	}
 
	R2 = 1 - SumSST/SumSSE;
}

转载请注明文章来自糗世界博客

Tags: , , ,

2 Responses to “用最小二乘算法求过零点的斜率”

  1. Liang Huang 说道:

    呵呵,我手头还有高数的书,上面有最小二乘法。不过现在都直接用Excel算了。

    [回复]

    admin 回复:

    @Liang Huang, 用Excel就是慢啊……如果一个星期要处理20条标准曲线,然后还要从上百个样品原文件里读取面积而后算浓度,两三个小时别的不干,就光copy paste了。

    [回复]

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">