项目需求对每一组数据进行曲线的拟合,拟合成对数,指数,一次线性或者二次线性中最符合要求的一条曲线
下面是工具类:
public class MathResult {
//线性公式y=ax+b
public static Object[] lineFitting(double x[], double y[]) { //分别为公式,R的平方值
int size = x.length;
double xmean = 0.0;
double ymean = 0.0;
double xNum = 0.0;
double yNum = 0.0;
double xyNum = 0;
double xNum2 = 0;
double yNum2 = 0;
double rss = 0;
double tss = 0;
double result[] = new double[6];
for (int i = 0; i < size; i++) {
xmean += x[i];
ymean += y[i];
xNum2 += x[i] * x[i];
yNum2 += y[i] * y[i];
xyNum += x[i] * y[i];
}
xNum = xmean;
yNum = ymean;
xmean /= size;
ymean /= size;
double sumx2 = 0.0f;
double sumxy = 0.0f;
for (int i = 0; i < size; i++) {
sumx2 += (x[i] - xmean) * (x[i] - xmean);
sumxy += (y[i] - ymean) * (x[i] - xmean);
}
double b = sumxy / sumx2;
double a = ymean - b * xmean;
result[0] = a;
result[1] = b;
double correlation = (xyNum - xNum * yNum / size) / Math.sqrt((xNum2 - xNum * xNum / size)
* (yNum2 - yNum * yNum / size));
LogUtils.e("相关系数:" + correlation);
result[2] = correlation;
for (int i = 0; i < size; i++) {
rss += (y[i] - (a + b * x[i])) * (y[i] - (a + b * x[i]));
tss += (y[i] - ymean) * (y[i] - ymean);
}
double r2 = 1 - (rss / (size - 1 - 1)) / (tss / (size - 1));
result[3] = r2;
result[4] = x.length;
result[5] = x.length - 1 - 1;
double format = format(result[0], 4);
String s = "";
if (format >= 0) {
s = " +" + format;
} else {
s = " -" + format;
}
// TODO: 2017/12/20 线性计算拟合优度的方法
double xsum = 0d;
for (int i = 0; i < x.length; i++) {
xsum += x[i];
}
double xavg = xsum / x.length;//x的平均值
double x2 = 0d;
for (int i = 0; i < x.length; i++) {
x2 += ((x[i] - xavg) * (x[i] - xavg));
}
double xrange = Math.sqrt(x2 / x.length);//x的标准差
double ysum = 0d;
for (int i = 0; i < y.length; i++) {
ysum += y[i];
}
double yavg = ysum / y.length;//y的平均值
double y2 = 0d;
for (int i = 0; i < y.length; i++) {
y2 += ((y[i] - yavg) * (y[i] - yavg));
}
double yrange = Math.sqrt(y2 / y.length);//y的标准差
double ori = 0d;
for (int i = 0; i < x.length; i++) {
ori += (((x[i] - xavg) / xrange) * ((y[i] - yavg) / yrange));
}
double R2 = format(Math.pow(ori / x.length, 2), 4);
LogUtils.e("拟合优度R的平方为" + R2);
LogUtils.e("公式:" + "y=" + format(result[1], 4) + "* X" + s);
return new Object[]{"Y=" + format(result[1], 4) + "* X " +
s, R2};
}
//
//多项式y=ax的平方+bx+c
// TODO: 2017/12/18 n表示多项式的次数,我们只需考虑到2次
public static Object[] dxsFitting(double x[], double y[], int n) {
double result[] = new double[n + 4];
WeightedObservedPoints obs = new WeightedObservedPoints();
for (int i = 0; i < x.length; i++) {
obs.add(x[i], y[i]);
}
final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(n);
final double[] coeff = fitter.fit(obs.toList());
for (int i = 0; i < coeff.length; i++) {
result[i] = coeff[i];
}
double s = getDxsR(x, y, coeff, 5);
result[n + 1] = x.length;
result[n + 2] = x.length - n - 1;
result[n + 3] = s;
String a1 = "";
String a2 = "";
String a3 = "";
a1 = "Y= " + format(result[2], 4) + "X^2";
if (format(result[1], 4) < 0) {
a2 = " -" + format(result[1], 4) + "* X";
} else {
a2 = " +" + format(result[1], 4) + " * X";
}
if (format(result[0], 4) < 0) {
a3 = " -" + format(result[0], 4);
} else {
a3 = " +" + format(result[0], 4);
}
LogUtils.e("公式:" + a1 + a2 + a3);
// TODO: 2017/12/18 计算R的平方
double ysum = 0d;
for (int i = 0; i < y.length; i++) {
ysum += y[i];
}
double yavg = ysum / y.length;//y的平均值
double sss = 0d;
for (int i = 0; i < x.length; i++) {
sss += Math.pow(y[i] - ((format(result[2], 4) * Math.pow(x[i], 2)) +
(format(result[1], 4) * x[i]) + format(result[0], 4)), 2);
}
double ssreg = 0d;
for (int i = 0; i < x.length; i++) {
ssreg += (y[i] - yavg) * (y[i] - yavg);
}
double R2 = format((1 - sss / ssreg), 4);
LogUtils.e("拟合优度R的平方为===" + R2); //拟合优度
return new Object[]{a1 + a2 + a3, R2};
}
// TODO: 2017/12/20 对数的拟合曲线
// TODO: 2017/12/14 0014 y=a+b*ln(x)
public static Object[] logFitting(double x[], double y[]) {
double yem = 0.0;
double y1 = 0.0;
double xem = 0.0;
double x1 = 0.0;
double x2 = 0.0;
double x3 = 0.0;
double avgx = 0.0;
double avgy = 0.0;
double dxy = 0.0;
double dx2 = 0.0;
double dy2 = 0.0;
double y2 = 0.0;
for (int i = 0; i < y.length; i++) {
yem += y[i];
}
avgy = (yem) / y.length;
for (int i = 0; i < y.length; i++) {
y2 += (y[i] - avgy);
}
for (int i = 0; i < y.length; i++) {
y1 += y[i] * Math.log(x[i]);
}
for (int i = 0; i < x.length; i++) {
xem += x[i];
}
avgx = (xem) / x.length;
for (int i = 0; i < x.length; i++) {
x1 += Math.log(x[i]);
}
for (int i = 0; i < x.length; i++) {
x2 += Math.log((x[i])) * Math.log((x[i]));
}
for (int i = 0; i < x.length; i++) {
if (i == 0) {
x3 = Math.log(x[i]);
} else {
x3 *= Math.log(x[i]);
}
}
for (int i = 0; i < x.length; i++) {
dxy += (x[i] - avgx) * (y[i] - avgy);
}
for (int i = 0; i < x.length; i++) {
dx2 += (x[i] - avgx) * (x[i] - avgx);
}
for (int i = 0; i < y.length; i++) {
dy2 += (y[i] - avgy) * (y[i] - avgy);
}
double A = format((((yem - ((x.length * y1 - yem * x1) / (x.length * x2 - x1 * x1)) * x1))) / x.length, 4);
double B = format(((x.length * y1 - yem * x1) / (x.length * x2 - x1 * x1)), 4);
LogUtils.e("计算的结果为b=" + B);
LogUtils.e("计算结果为a=" + A);
String fb = "";
if (B >= 0) {
fb = "+" + B + "";
} else {
fb = "-" + B;
}
LogUtils.e("公式: Y= " + A + fb + "*lnX");
// TODO: 2017/12/18 计算R的平方
double ysum = 0d;
for (int i = 0; i < y.length; i++) {
ysum += y[i];
}
double yavg = ysum / y.length;//y的平均值
double sss = 0d;
for (int i = 0; i < x.length; i++) {
sss += Math.pow(y[i] - (A + B * Math.log(x[i])), 2);
}
double ssreg = 0d;
for (int i = 0; i < x.length; i++) {
ssreg += (y[i] - yavg) * (y[i] - yavg);
}
double R2 = format((1 - sss / ssreg), 4);
LogUtils.e("拟合优度R的平方为===" + R2); //拟合优度
return new Object[]{"Y= " + A + fb + "*lnX", R2};
}
// TODO: 2017/12/20 计算指数
// TODO: 2017/12/20 y = b*exp(ax)
public static Object[] expFitting(double x[], double y[]) {
double[] oriY = new double[y.length];
for (int i = 0; i < y.length; i++) {
oriY[i] = y[i];
}
int size = x.length;
double xmean = 0.0;
double ymean = 0.0;
double rss = 0;
double tss = 0;
double result[] = new double[5];
for (int i = 0; i < size; i++) {
xmean += x[i];
y[i] = Math.log(y[i]);
ymean += y[i];
}
xmean /= size;
ymean /= size;
double sumx2 = 0.0f;
double sumxy = 0.0f;
for (int i = 0; i < size; i++) {
sumx2 += (x[i] - xmean) * (x[i] - xmean);
sumxy += (y[i] - ymean) * (x[i] - xmean);
}
double b = sumxy / sumx2;
double a = ymean - b * xmean;
for (int i = 0; i < size; i++) {
rss += (y[i] - (a + b * x[i])) * (y[i] - (a + b * x[i]));
tss += (y[i] - ymean) * (y[i] - ymean);
}
double r2 = 1 - (rss / (size - 1 - 1)) / (tss / (size - 1));
a = Math.exp(a);
result[0] = a;
result[1] = b;
result[2] = x.length;
result[3] = x.length - 2;
result[4] = r2;
double B = format(result[1], 4);
double A = format(result[0], 4);
LogUtils.e("公式:" + "Y= " + A + "*e^(" + B + "*X)");
// TODO: 2017/12/18 计算R的平方
double ysum = 0d;
for (int i = 0; i < oriY.length; i++) {
ysum += oriY[i];
}
double yavg = ysum / oriY.length;//y的平均值
double sss = 0d;
for (int i = 0; i < x.length; i++) {
sss += Math.pow((oriY[i] - (A * (Math.exp((B * x[i]))))), 2);
}
double ssreg = 0d;
for (int i = 0; i < x.length; i++) {
ssreg += (oriY[i] - yavg) * (oriY[i] - yavg);
}
double R2 = format((1 - sss / ssreg), 4);
LogUtils.e("拟合优度R的平方为===" + R2); //拟合优度
return new Object[]{"Y= " + A + "*e^(" + B + "*X)", R2};
}
/**
* 获得决定系数
*
* @param coeff
* @return
*/
private static double getDxsR(double x[], double y[], double coeff[], int n) {
int size = x.length;
double ymean = 0.0;
double rss = 0;
double tss = 0;
for (int i = 0; i < size; i++) {
ymean += y[i];
}
ymean /= size;
for (int i = 0; i < size; i++) {
rss += (y[i] - getDxsValueByX(x[i], coeff)) * (y[i] - getDxsValueByX(x[i], coeff));
tss += (y[i] - ymean) * (y[i] - ymean);
}
double r2 = 1 - (rss / (size - n - 1)) / (tss / (size - 1));
return r2;
}
/**
* 通过X获得Y的值
*
* @param x
* @param coeff
* @return
*/
private static double getDxsValueByX(double x, double coeff[]) {
int size = coeff.length;
double result = coeff[0];
for (int i = 1; i < size; i++) {
result += coeff[i] * Math.pow(x, i);
}
return result;
}
//四舍五入
public static double format(double d, int index) {
BigDecimal bd = new BigDecimal(d);
return bd.setScale(index, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}