最近在弄一些數據趨勢判斷該方面的東西,下面代碼是網友使用最小二乘法做的數據擬合算法的java實現
public class PolyFitForcast {
public PolyFitForcast() {
}
/**
* <p>
* 函數功能:最小二乘法曲線擬合
* </p>
* <p>
* 方程:Y = a(0) + a(1) * (X - X1)+ a(2) * (X - X1)^2 + ..... .+ a(m) * (X -
* X1)^m X1爲X的平均數
* </p>
*
* @param x
* 實型一維數組,長度爲 n. 存放給定 n 個數據點的 X 座標
* @param y
* 實型一維數組,長度爲 n.存放給定 n 個數據點的 Y 座標
* @param n
* 變量。給定數據點的個數
* @param a
* 實型一維數組,長度爲 m.返回 m-1 次擬合多項式的 m 個係數
* @param m
* 擬合多項式的項數,即擬合多項式的最高次數爲 m-1. 要求 m<=n 且m<=20。若 m>n 或 m>20
* ,則本函數自動按 m=min{n,20} 處理.
* <p>
* Date:2007-12-25 16:21 PM
* </p>
* @author qingbao-gao
* @return 多項式係數存儲數組
*/
public static double[] PolyFit(double x[], double y[], int n, double a[],
int m) {
int i, j, k;
double z, p, c, g, q = 0, d1, d2;
double[] s = new double[20];
double[] t = new double[20];
double[] b = new double[20];
double[] dt = new double[3];
for (i = 0; i <= m - 1; i++) {
a[i] = 0.0;
}
if (m > n) {
m = n;
}
if (m > 20) {
m = 20;
}
z = 0.0;
for (i = 0; i <= n - 1; i++) {
z = z + x[i] / (1.0 * n);
}
b[0] = 1.0;
d1 = 1.0 * n;
p = 0.0;
c = 0.0;
for (i = 0; i <= n - 1; i++) {
p = p + (x[i] - z);
c = c + y[i];
}
c = c / d1;
p = p / d1;
a[0] = c * b[0];
if (m > 1) {
t[1] = 1.0;
t[0] = -p;
d2 = 0.0;
c = 0.0;
g = 0.0;
for (i = 0; i <= n - 1; i++) {
q = x[i] - z - p;
d2 = d2 + q * q;
c = c + y[i] * q;
g = g + (x[i] - z) * q * q;
}
c = c / d2;
p = g / d2;
q = d2 / d1;
d1 = d2;
a[1] = c * t[1];
a[0] = c * t[0] + a[0];
}
for (j = 2; j <= m - 1; j++) {
s[j] = t[j - 1];
s[j - 1] = -p * t[j - 1] + t[j - 2];
if (j >= 3)
for (k = j - 2; k >= 1; k--) {
s[k] = -p * t[k] + t[k - 1] - q * b[k];
}
s[0] = -p * t[0] - q * b[0];
d2 = 0.0;
c = 0.0;
g = 0.0;
for (i = 0; i <= n - 1; i++) {
q = s[j];
for (k = j - 1; k >= 0; k--) {
q = q * (x[i] - z) + s[k];
}
d2 = d2 + q * q;
c = c + y[i] * q;
g = g + (x[i] - z) * q * q;
}
c = c / d2;
p = g / d2;
q = d2 / d1;
d1 = d2;
a[j] = c * s[j];
t[j] = s[j];
for (k = j - 1; k >= 0; k--) {
a[k] = c * s[k] + a[k];
b[k] = t[k];
t[k] = s[k];
}
}
dt[0] = 0.0;
dt[1] = 0.0;
dt[2] = 0.0;
for (i = 0; i <= n - 1; i++) {
q = a[m - 1];
for (k = m - 2; k >= 0; k--) {
q = a[k] + q * (x[i] - z);
}
p = q - y[i];
if (Math.abs(p) > dt[2]) {
dt[2] = Math.abs(p);
}
dt[0] = dt[0] + p * p;
dt[1] = dt[1] + Math.abs(p);
}
return a;
}// end
/**
* <p>
* 對X軸數據節點球平均值
* </p>
*
* @param x
* 存儲X軸節點的數組
* <p>
* Date:2007-12-25 20:21 PM
* </p>
* @author qingbao-gao
* @return 平均值
*/
public static double average(double[] x) {
double ave = 0;
double sum = 0;
if (x != null) {
for (int i = 0; i < x.length; i++) {
sum += x[i];
}
ave = sum / x.length;
}
return ave;
}
/**
* <p>
* 由X值獲得Y值
* </p>
* @param x
* 當前X軸輸入值,即爲預測的月份
* @param xx
* 當前X軸輸入值的前X數據點
* @param a
* 存儲多項式係數的數組
* @param m
* 存儲多項式的最高次數的數組
* <p>
* Date:2007-12-25 PM 20:07
* </p>
* @return 對應X軸節點值的Y軸值
*/
public static double getY(double x, double[] xx, double[] a, int m) {
double y = 0;
double ave = average(xx);
double l = 0;
for (int i = 0; i < m; i++) {
l = a[0];
if (i > 0) {
y += a[i] * Math.pow((x - ave), i);
}
}
return (y + l);
}
public static void main(String[] args) throws Exception{
double[] test_xx = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,
51,52,53,54,55,56,57,58,59};// 15
double[] ss = {
9880,10000,9880,10088,9958,9869,9712,9670,9719,9625,9416,
9238,8962,9034,9375,9555,8162,8589,8119,8112,8092,8105,
7821,7943,8086,7825,7914,7804,7789,7903,7630,7666,
7545,7632,7619,7582,7427,7499,7463,7384,7315,7092,
7123,6911,7024,7016,7009,6929,7093,6972,7008,6689,
6793,6805,6835,6553,6659,6713,6757,6581};
int mmm = ss.length;
int m = 3;
double[] a = new double[test_xx.length];
double[] aa = PolyFit(test_xx, ss, mmm, a, m);
for(int i=0;i<mmm;i++){
System.out.println("擬合-->" + getY(i, test_xx, aa, m));
}
}
}