您的位置:首页 > 编程语言 > Java开发

数据挖掘笔记-分类-回归算法-最小二乘法

2014-06-21 21:14 501 查看
开始学习回归算法,先看下最小乘法在回归算法里面的应用。相关概念理论如下:
最小二乘法
我们在研究两个变量(x, y)之间的相互关系时,通常可以得到一系列成对的数据(x1, y1、x2,
y2... xm , ym);将这些数据描绘在x -y直角座标系中(如图1), 若发现这些点在一条直线附近,可以令这条直线方程如(式1-1)。 



Y计= a0 + a1 X
                (式1-1) 

其中:a0、a1 是任意实数 

为建立这直线方程就要确定a0和a1,应用《最小二乘法原理》,将实测值Yi与利用(式1-1)计算值(Y计= a0 + a1 X)的离差(Yi - Y计)的平方和`〔∑(Yi -
Y计)2〕最小做为“优化判据”。 

令: φ = ∑(Yi - Y计)2               (式1-2) 

把(式1-1)代入(式1-2)中得: 

φ = ∑(Yi - a0 - a1 Xi)2             
 (式1-3) 

当∑(Yi-Y计)平方最小时,可用函数 φ 对a0、a1求偏导数,令这两个偏导数等于零。 


            (式1-4) 


         (式1-5)  
亦即: 

m a0 + (∑Xi ) a1 = ∑Yi              (式1-6) 

(∑Xi ) a0 + (∑Xi2 ) a1 = ∑(Xi,
Yi)          (式1-7) 

得到的两个关于a0、 a1为未知数的两个方程组,解这两个方程组得出:

a0 = ∑Yi / m - a1 * ∑Xi / m                                 (式1-8)

a1 = [m∑(XiYi) - ∑Xi * ∑Yi] / [m∑(Xi^2) - (∑Xi)^2]  (式1-9) 
其中m为样本容量

这时把a0、a1代入(式1-1)中, 此时的(式1-1)就是我们回归的元线性方程即:数学模型。 

在回归过程中,回归的关联式是不可能全部通过每个回归数据点(x1, y1、 x2, y2...xm,ym),为了判断关联式的好坏,可借助相关系数“R”,统计量“F”,剩余标准偏差“S”进行判断;“R”越趋近于
1 越好;“F”的绝对值越大越好;“S”越趋近于 0 越好。 其中:

R = [∑XiYi - m (∑Xi / m)(∑Yi / m)]/ SQR{[∑Xi2 -
m (∑Xi / m)2][∑Yi2 - m (∑Yi / m)2]}
       (式1-10) 

最小三乘法
促上述情况之外,我们在研究实际中两个变量(x, y)之间的相互关系时,对一系列成对的数据(x1,y1、x2,y2 ... xm,ym);将这些数据描绘在x - y直角座标系(如图2)中,发现这些点在一条曲线附近,假设这条曲线的一元非线性方程如(式2-1)。



Y计 = a0 + a1 Xk            (式2-1) 

其中:a0、a1、k是任意实数 

为建立曲线方程,就要确定a0 、a1和 k 值,应用《最小二乘法》同样的方法, 将实测值Yi与计算值 Y计(Y计 = a0 +
a1 Xik)的离差 (Yi - Y计)的平方和〔∑(Yi -
Y计)2〕为依据:

令: φ = ∑(Yi - Y计)2           (式2-2)

把(式2-1)代入(式2-2)中得:

φ = ∑(Yi - a0 - a1 Xik )2       (式2-3) 

用函数 φ 分别对a0、a1 和 k 求偏导数,令这三个偏导数等于零即:


         (式2-4) 


     (式2-5) 


    (式2-6) 

得到三个关于a0、a1 和 k,为未知数的三元方程组,解方程组即可得到数学模型。 这里就不再详细陈述了。有兴趣的小伙伴可以自己算出相应的值。

最小三乘法和最小二乘法比较:

1.“最小三乘法”利用计算幂值,使回归模型函数曲线以不同曲率弯曲,来更好的拟和不同曲率的曲线。它省去了“最小二乘法”中繁琐的建机理模型和线性化处理,使回归模型与数据拟和更好。

2.对多维非线性数据回归,不用“偏最小二乘法”的每个因素逐一与目标函数回归建模,再把所有模型捆绑成最终模型的方法,而是所有因素与目标函数,同时一次回归成数学模型,在回归时,它不但考虑因素对目标函数的贡献,还把因素之间的影响考虑进去,这样的模型要比用“偏最小二乘法”回归的模型准确。
3.“最小二乘法”数据回归一因素数据只有一元 “X”, “最小三乘法” 数据回归一因素数据可有若干个元

“Xk1”、“Xk2” 、… “Xkn” 如(式3-2), 利用这一特性,可使回归模型拟和数据更准确。 
Y计 = a0 + a1 Xk1 + a2 Xk2 +...+ an X kn                   (式3-2)

选择回归参数注意问题 

1、当一因素数据中有 0 值时, 此因素数据不可作除数和取对数;可把此维数据加上一个数,使它大于零。 

2、当一因素数据中有负数都有时,此因素数据不可做回归计算;可把此维数据乘上一个负数,使它大于零。

3、某因素数据取幂时,不可太大和太小,否则回归计算机会中断溢出;有时回归出的模型,不能逆运算。

下面是用Java语言简单实现的最小二乘法算法:

public class LeastSquaresBuilder {

//初始化数据
private List<Point> initializeData() {
List<Point> points = new ArrayList<Point>();
points.add(new Point(1, 110));
points.add(new Point(2, 120));
points.add(new Point(3, 130));
points.add(new Point(4, 140));
points.add(new Point(5, 150));
points.add(new Point(6, 160));
points.add(new Point(7, 170));
points.add(new Point(8, 180));
points.add(new Point(9, 190));
return points;
}

/**
* Y = a0 + a1 * X
* a0 = ∑Yi / m - a1 * ∑Xi / m
* a1 = [m∑(XiYi) - ∑Xi * ∑Yi] / [m∑(Xi^2) - (∑Xi)^2]
* 计算a0、a1
*/
private double[] calculate(List<Point> points) {
double[] xParameters = extract(points, "X");
double[] yParameters = extract(points, "Y");
double m = points.size();
double xSum = sum(xParameters, false);
double ySum = sum(yParameters, false);
double xySum = sum(xParameters, yParameters);
double xxSum = sum(xParameters, true);
double p1 = m * xySum - xSum * ySum;
double p2 = m * xxSum - Math.pow(xSum, 2);
double a1 =  p1 / p2;
double a0 = ySum / m - a1 * xSum / m;
System.out.println("Y = " + a0 + " + " + a1 + " * X");
return new double[]{a0 , a1};
}

//预测X的值Y
private double predict(double[] a0_a1, double x) {
if (a0_a1.length != 2) {
throw new RuntimeException("error");
}
return a0_a1[0] + a0_a1[1] * x;
}

//计算∑(Xi) 或则 ∑(Xi^2)
private double sum(double[] parameters, boolean isSquare) {
double result = 0.0;
for (double parameter : parameters) {
result += isSquare ? Math.pow(parameter, 2) : parameter;
}
return result;
}

//计算∑(XiYi)
private double sum(double[] xParameters, double[] yParameters) {
double result = 0.0;
for (int i = 0, len = xParameters.length; i < len; i++) {
result += xParameters[i] * yParameters[i];
}
return result;
}

//抽取某一维度点集合
private double[] extract(List<Point> points, String type) {
double[] result = new double[points.size()];
int index = 0;
for (Point point : points) {
if ("X".equals(type)) {
result[index++] = point.getX();
} else if ("Y".equals(type)) {
result[index++] = point.getY();
}
}
return result;
}

public void build() {
List<Point> points = initializeData();
double[] a0_a1 = calculate(points);
double x = 10;
double result = predict(a0_a1, x);
System.out.println("predict " + x + " result: " + result);
}

public static void main(String[] args) {
LeastSquaresBuilder builder = new LeastSquaresBuilder();
builder.build();
}
}
代码托管:https://github.com/fighting-one-piece/repository-datamining.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息