2018年华为精英挑战赛初赛预测算法Java实现

我使用各种算法预测,包括多元线性回归(从二元到七元)、交叉线性回归、局部加权线性回归、ARMA、自回归等,对比发现三次指数平滑效果较好,java源码如下:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Predict {
public static String[] predictVm(String[] ecsContent, String[] inputContent) {

/** =========do your work here========== **/
/**输入数据
* server_info 服务器信息(cpu、内存)
* ecsTypes 要预测的虚拟机类型个数
* flavors 要预测的虚拟机列表
* optResource 要优化的资源维度
* start_time/end_time/predictTime 预测开始时间、结束时间以及时间跨度
* numOfHistory 历史数据
*/
int[] server_info=new int[3];
int ecsTypes=0;
List<String> flavors = new ArrayList<String>();
String optResource;
String start_time;
String end_time;
int predictTime = 0;
int[][] numOfHistory = null;
/**输出数据
* ecsPredict 对应各类虚拟机预测数目
* results 放置阶段结果,也是最终的结果
*/
int[] ecsPredict ;
String[] results=null;
/**存虚拟机请求的历史数据
* 历史请求数据格式:
* 56498c50-84e4 flavor15 2015-01-01 19:03:32
56498c51-8cb9 flavor15 2015-01-01 19:03:34
56498c52-a50e flavor8 2015-01-01 23:26:04
56498c53-a241 flavor2 2015-01-02 18:25:23
56498c54-8528 flavor8 2015-01-02 21:03:49
*/
List<String> history = new ArrayList<String>();
for (int i = 0; i < ecsContent.length; i++) {
if (ecsContent[i].contains(" ")
&& ecsContent[i].split("\\s+").length == 4) {
String[] array = ecsContent[i].split("\\s+");
// String uuid = array[0]; //uuid不需要存,浪费空间
String flavorName = array[1];
String createTime = array[2];
history.add(flavorName + " " + createTime);
}
}
/**存服务器规格、虚拟机规格、优化资源维度、预测时间
* input中数据格式:
56 128 1200

5
flavor1 1 1024
flavor2 1 2048
flavor3 1 4096
flavor4 2 2048
flavor5 2 4096

CPU

2015-02-20 00:00:00
2015-02-27 00:00:00
*/
//去掉input中的空格
List<String> temp=new ArrayList<String>();
for (int i = 0; i < inputContent.length; i++) {
if(inputContent[i].trim().length()==0)
continue;
temp.add(inputContent[i].trim());
}
//去掉input中的空格结束
//读input中的数据进变量
String[] array=temp.get(0).split("\\s+");
server_info[0]=Integer.parseInt(array[0]);
server_info[1]=Integer.parseInt(array[1]);
server_info[2]=Integer.parseInt(array[2]);
ecsTypes=Integer.parseInt(temp.get(1));
for(int i=0;i<ecsTypes;i++) {
flavors.add(temp.get(2+i));
}
optResource=temp.get(ecsTypes+2).trim();
start_time=temp.get(ecsTypes+3);
end_time=temp.get(ecsTypes+4);
try {
//System.out.println(start_time);
predictTime=(int)getInterval(start_time,end_time);
} catch (Exception e) {
e.printStackTrace();
}
String[] ecsNames=new String[flavors.size()];
for(int i=0;i<flavors.size();i++) {
ecsNames[i] = flavors.get(i).split("\\s+")[0].trim();
}
//读input中的数据进变量结束
//返回待预测虚拟机历史数据的汇总
try {
numOfHistory=getHistory(ecsNames,history);
} catch (Exception e) {
e.printStackTrace();
}
//返回待预测虚拟机历史数据的汇总结束
ecsContent=null;inputContent=null;//释放ecsContent inputContent? @修改
//******************************************************************预测阶段(算ecsPredict数组)*************************************************//
ecsPredict=new int[ecsTypes];//第一阶段要预测的数组
/**写了十几个模型,每个模型都好几个参数可以调,而且每个参数结果相差非常大,比赛第一天程序错误浪费几次计划,不敢再往下调
* 郁闷
*/
/**对历史请求数据降噪
* 降噪暂时想不出合适方法 根据调参的结果降噪不降噪都没用
*/
numOfHistory=denoise(numOfHistory); //调参,针对虚拟机种类调参
/**线性回归和局部加权线性回归都试过,还是平均数好点
* 我准备这样做:因为长期内是有趋势性,我取前七天的值,加上这个值比上一个七天多出的值作为结果,保证结果大于0
*/
// for(int i=0;i<numOfHistory.length;i++) {
// int len=numOfHistory[i].length;
// //求预测点前七天的值
// int sum1=0;
/// for(int j=0;j<predictTime;j++) {
/// sum1+=numOfHistory[i][len-1-j];
// }
// //求预测点前面第二个period的总数
// int sum2=0;
// for(int j=len-2*predictTime;j<len-predictTime;j++) {
// sum2+=numOfHistory[i][j];
// }
// //预测,取绝对值
// ecsPredict[i]=sum1+(sum1-sum2);
// //如果预测值小于0,取为最近period的值
// if(ecsPredict[i]<0) {
// ecsPredict[i]=sum1;
// }
// }
/**法13:三次指数平滑模型
* 实在没办法了,进不了三十六强啊
*/
/**大佬说将请求为0的天数变为平均数
*
*/
double alpha = 0.5, beta = 0.3, gamma = 0.1; //可调参
int period = predictTime, m = predictTime; //可调参
boolean debug = false;
double[] real=new double[numOfHistory[0].length];
for(int i=0;i<numOfHistory.length;i++) {
for(int j=0;j<real.length;j++)
real[j]=numOfHistory[i][j];
double[] res = TripleExponentialImpl.forecast(real, alpha, beta, gamma, period, m, debug); //有一个方法可调参
double total=0;
for(int j=real.length;j<res.length;j++) {
total+=res[j];
}
ecsPredict[i]=(int)Math.ceil(total); //可调参,计算之前取整,结果*k+b
}

for(int i=0;i<ecsPredict.length ;i++) {
if(ecsPredict[i]<0)
ecsPredict[i]=0;
}

/**法7:网友推荐的交叉线性回归(4元回归)
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getFourX(numOfHistory[i],predictTime);//根据时间序列和预测期获得4元回归的X数组
// double[] Y=CrossRegre.getFourY(numOfHistory[i],predictTime);//根据时间序列和预测期获得4元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[5];//4元回归系数
// Regression._LineRegression(X,Y,K,4,X.length);
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3+K[4]*X4)); //可调参,计算之前取整,*k+b
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
//-----------------------------------------------------------------下列方法弃用------------------------------------------
/**法1:最后一天,要放大招了,一元局部加权线性回归
* 参数如果调不好就放弃,别人调参能上82
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getFirX(numOfHistory[i],predictTime);//根据时间序列和预测期获得1元回归的X数组
// double[] Y=CrossRegre.getFirY(numOfHistory[i],predictTime);//根据时间序列和预测期获得1元回归的Y数组
// //计算要预测y对应x
// /** x1 y
// *角标 0 period
// * 1 1+period
// * ...
// * n-2*period n-period
// 预测 n-period n
// */
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// double[] pre_x=new double[1];
// pre_x[0]=X1;
// //调用局部加权线性回归类进行预测
// double[] K=Lwlr.getPara(X,Y,0.5,pre_x);//k0 k1 //调参
// //System.out.println("第"+(i+1)+"个虚拟机回归方程:y="+K[0]+"+"+K[1]+"X1");
// //进行预测
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1))+10;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
/**法2:2元局部加权线性回归
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getSecX(numOfHistory[i],predictTime);//根据时间序列和预测期获得2元回归的X数组
// double[] Y=CrossRegre.getSecY(numOfHistory[i],predictTime);//根据时间序列和预测期获得2元回归的Y数组
// //计算要预测y对应x
// /** x1 x2 y
// *角标 0 1 1+period
// * 1 2 2+period
// * ...
// * n-2*period-1 n-2*period n-period
// 预测 n-period-1 n-period n
// */
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// double[] pre_x=new double[2];
// pre_x[0]=X1;pre_x[1]=X2;
// //调用局部加权线性回归类进行预测
// double[] K=Lwlr.getPara(X,Y,16,pre_x);//k0 k1 //调参
// //进行预测
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2));
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
/**法3:3元局部加权线性回归
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getThreeX(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的X数组
// double[] Y=CrossRegre.getThreeY(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的Y数组
// //计算要预测y对应x
// /** x1 x2 x3 y
// *角标 0 1 2 2+period
// * 1 2 3 3+period
// * ...
// * n-2*period-2 n-2*period-1 n-2*period n-period
// 预测 n-period-2 n-period-1 n-period n
// */
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// double[] pre_x=new double[3];
// pre_x[0]=X1;pre_x[1]=X2;pre_x[2]=X3;
// //调用局部加权线性回归类进行预测
// double[] K=Lwlr.getPara(X,Y,3,pre_x);//k0 k1 //调参
// //进行预测
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3));
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
/**法4:4元局部加权线性回归
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getFourX(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的X数组
// double[] Y=CrossRegre.getFourY(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的Y数组
// //计算要预测y对应x
// /** x1 x2 x3 x4 y
// *角标 0 1 2 3 3+period
// * 1 2 3 4 4+period
// * ...
// * n-2*period-3 n-2*period-2 n-2*period-1 n-2*period n-period
// 预测 n-period-3 n-period-2 n-period-1 n-period n
// */
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// double[] pre_x=new double[4];
// pre_x[0]=X1;pre_x[1]=X2;pre_x[2]=X3;pre_x[3]=X4;
// //调用局部加权线性回归类进行预测
// double[] K=Lwlr.getPara(X,Y,3,pre_x);//改成2 0.2都跑不出来 //调参
// //进行预测
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3));
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int i=1;i<ecsPredict.length ;i++) {
// System.out.print(ecsPredict[i]+" ");
// }
/**法5:网友推荐的交叉线性回归(3元回归)最高78.541 这个方法可以上榜但是预测偏低(可能是因为去噪不好),进不了32强
* 1、如预测期是7,一个3元交叉回归模型要找到t时间至t+6的用户请求与(t-7,t-1)、(t-8,t-2)、(t-9,t-3)时间段用户请求的回归关系
* 2、那么关键是处理历史数据数组了:假设历史数据数组长度是n
* x1 x2 x3 y
*角标 0 1 2 2+period
* 1 2 3 3+period
* ...
* n-2*period-2 n-2*period-1 n-2*period n-period
预测 n-period-2 n-period-1 n-period n
*另外还得写一个函数,求数组某个角标开始的m个元素的和
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getThreeX(numOfHistory[i],predictTime);//根据时间序列和预测期获得三元回归的X数组
// double[] Y=CrossRegre.getThreeY(numOfHistory[i],predictTime);//根据时间序列和预测期获得三元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[4];//3元回归系数
// Regression._LineRegression(X,Y,K,3,X.length);
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3)); //可调参,计算之前取整,*k+b
// //+5 76.883进64强 +10 78.427 +13 77.822 +14 77.824 +15 78.541 +16 78.04 +18 77.651
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int i=1;i<ecsPredict.length ;i++) {
// System.out.print(ecsPredict[i]+" ");
// }
/**法6:试试改进交叉线性回归(3元回归),注意结果不能是负数,样本量太少会报错
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getThreeX(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的X数组
// double[] Y=CrossRegre.getThreeY(numOfHistory[i],predictTime);//根据时间序列和预测期获得3元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[4];//3元回归系数
// double res=Regression.optLineRegression(X,Y,K,3,X.length,0.98); //可调参,样本保有率
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3)); //可调参,计算之前取整,结果*k+b
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int i=1;i<ecsPredict.length ;i++) {
// System.out.print(ecsPredict[i]+" ");
// }

/**法8:试试改进交叉线性回归(4元回归)
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getFourX(numOfHistory[i],predictTime);//根据时间序列和预测期获得4元回归的X数组
// double[] Y=CrossRegre.getFourY(numOfHistory[i],predictTime);//根据时间序列和预测期获得4元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[5];//4元回归系数
// Regression.optLineRegression(X,Y,K,4,X.length,0.98); //可调参,样本保有率
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3+K[4]*X4)); //可调参,计算之前取整,结果*k+b
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
/**法9:五元回归
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getFiveX(numOfHistory[i],predictTime);//根据时间序列和预测期获得5元回归的X数组
// double[] Y=CrossRegre.getFiveY(numOfHistory[i],predictTime);//根据时间序列和预测期获得5元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[6];//5元回归系数
// //Regression.optLineRegression(X,Y,K,5,X.length,0.98); //可调参,样本保有率
// Regression._LineRegression(X,Y,K,5,X.length);
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-4, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X5=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3+K[4]*X4+K[5]*X5)); //可调参,计算之前取整,结果*k+b
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
/**法10:六元回归
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getSixX(numOfHistory[i],predictTime);//根据时间序列和预测期获得6元回归的X数组
// double[] Y=CrossRegre.getSixY(numOfHistory[i],predictTime);//根据时间序列和预测期获得6元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[7];//6元回归系数 //可调 2元 4元
// Regression.optLineRegression(X,Y,K,6,X.length,0.98); //可调参,样本保有率
// // Regression._LineRegression(X,Y,K,6,X.length);
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-5, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-4, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X5=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X6=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3+K[4]*X4+K[5]*X5+K[6]*X6)); //可调参,计算之前取整,结果*k+b
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
/**法11:七元回归
*
*/
// for(int i=0;i<numOfHistory.length;i++) {
// //调用CrossRegre得到样本
// double[][] X=CrossRegre.getSevX(numOfHistory[i],predictTime);//根据时间序列和预测期获得三元回归的X数组
// double[] Y=CrossRegre.getSevY(numOfHistory[i],predictTime);//根据时间序列和预测期获得三元回归的Y数组
// //调用线性回归类进行预测
// double[] K=new double[8];//6元回归系数
// //Regression.optLineRegression(X,Y,K,7,X.length,0.98); //可调参,样本保有率
// Regression._LineRegression(X,Y,K,7,X.length);
// double X1=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-6, predictTime);
// double X2=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-5, predictTime);
// double X3=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-4, predictTime);
// double X4=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-3, predictTime);
// double X5=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-2, predictTime);
// double X6=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime-1, predictTime);
// double X7=CrossRegre.sum(numOfHistory[i], numOfHistory[i].length-predictTime, predictTime);
// ecsPredict[i]=(int)Math.ceil((K[0]+K[1]*X1+K[2]*X2+K[3]*X3+K[4]*X4+K[5]*X5+K[6]*X6+K[7]*X7)); //可调参,计算之前取整,结果*k+b
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
// for(int i=0;i<ecsPredict.length ;i++) {
// if(ecsPredict[i]<0)
// ecsPredict[i]=0;
// }
/**-------------------------------------------------下列预测方法在比赛最终阶段弃用-----------------------------------------------------------*/
/**法12:自回归模型
* 因公式推导原因暂时放弃
*/

/**法14:直接取平均数
* 结果很糟,还不如直接取后几天作为预测
*/
// for(int i=0;i<ecsPredict.length;i++) {
// int sum3=0;
// for(int j=0;j<numOfHistory[i].length;j++) {
// sum3+=numOfHistory[i][j];
// }
// ecsPredict[i]=sum3/numOfHistory[0].length*predictTime;
// }
// for(int j=0;j<ecsPredict.length ;j++){
// System.out.print(ecsPredict[j]+" ");
// }
/**法15:差分完再平均
* 输入:虚拟机历史数据、预测期
* 输出:对应虚拟机预测期总数(数组)
*/
// for(int i=0;i<ecsPredict.length;i++) {
// AvgModel avmodel=new AvgModel(numOfHistory[i],predictTime);
// ecsPredict[i]=avmodel.predict();
// }

/**法16:ARIMA预测
*输入参数:第i种虚拟机请求数目、预测期天数
*返回: 要预测虚拟机在预测期的预测总数
*/
// for(int i=0;i<ecsPredict.length;i++) {
// ARIMAModel arima=new ARIMAModel(newData[i],predictTime);
// ecsPredict[i]=arima.predict();
// }
/**法17:指数平滑法对每种虚拟机进行预测(该方法只作为应急备选方法)
* 知网的那篇论文乱七八糟公式,实现效果非常差
* 我自己实现的一篇论文的方法以及用别人现成代码都试了,效果极其糟糕,不知道是我没理解透彻还是方法本身就有问题
*/
// for(int i=0;i<flavors.size();i++) {
// Exp_smoothing E =new Exp_smoothing(numOfHistory[i],predictTime,0.7);
// E.init();
// int num = E.getTotalNum();
// ecsPredict[i]=num;
// }
/**注意:第一阶段预测结果如果是0或者负数第二阶段会崩,这点要注意
*
*/
//************************************************************************放置阶段*************************************************************//
/**动态规划算法
* 首先要把第一阶段预测的虚拟机的数据结构处理成一个列表然后传给动态规划算法
* 返回值是字符串,包含预测和放置两个阶段的结果,并作为最终结果,程序结束
*/
/**处理第一阶段返回结果
* flavor1 1 1024 3
flavor2 1 2048 4
flavor3 1 4096 6
flavor4 2 2048 0
flavor5 2 4096 3
*/
ArrayList<Ecs> Ecses=new ArrayList<Ecs>();
for(int i=0;i<flavors.size();i++) {
String name=flavors.get(i).split("\\s+")[0].trim();
int cpu=Integer.parseInt(flavors.get(i).split("\\s+")[1].trim());
int eme =Integer.parseInt(flavors.get(i).split("\\s+")[2].trim());
int forecast=ecsPredict[i];
Ecs e =new Ecs(name,cpu,eme,forecast);
Ecses.add(e);
}
//调动态规划求解
Bag bag=new Bag(Integer.parseInt(array[0]), Integer.parseInt(array[1]));
DP dp=new DP(Ecses,optResource,bag);
dp.init();
results = dp.getResult();
//输出结果
return results;
}
/**获取两段时间的时间间隔
* @param startTime 开始时间
* @param endTime 结束时间
* @return 开始时间与结束时间之间的天数
* @throws Exception
* "2015-01-01","2015-01-02"返回结果 1
*/
public static long getInterval(String startTime,String endTime) throws Exception {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = df.parse(endTime);
Date d2 = df.parse(startTime);
long diff = d1.getTime() - d2.getTime();
long days = diff / (1000 * 60 * 60 * 24);
return days;
}
/**获取虚拟机请求数目数组
* @param flavors 需要优化的虚拟机(如flavor1 flavor2......)
* @param history 所有虚拟机的历史请求数据(字符串列表)
* @return 对应各虚拟机的历史请求数据(二维数组)
* @throws Exception
* 下面是history数据格式:
* flavor15 2015-01-01 19:03:32
flavor15 2015-01-01 19:03:34
flavor8 2015-01-01 23:26:04
flavor2 2015-01-02 18:25:23
flavor8 2015-01-02 21:03:49
*/
public static int[][] getHistory(String[] flavors,List<String> history) throws Exception {//history已经把uid去掉了
//获取测试期长度
String startTime=history.get(0).split("\\s+")[1];
String endTime=history.get(history.size()-1).split("\\s+")[1];
long days= getInterval(startTime,endTime);
int[][] result=new int[flavors.length][1+(int)days];//这个地方注意+1
//获取测试期长度结束
//遍历测试数据
for(int i=0;i<history.size();i++) {
for(int j=0;j<flavors.length;j++) {
if(history.get(i).split("\\s+")[0].equalsIgnoreCase(flavors[j])) {
String tempTime=history.get(i).split("\\s+")[1];
int tempDays=(int)getInterval(startTime,tempTime);
result[j][tempDays]++;
break;
}
}
}
//遍历测试数据结束
return result;
}
/**数据降噪 这部分也是优化空间最大的一块,不稳定性极高 //可调参
* @param numOfHistory 各个虚拟机历史数据的二维数组
* 处理方法:均值正负3西格玛的数据,先改成0,再改成均值
* @return 异常值已经处理过的历史数据的二维数组
*/
public static int[][] denoise(int[][] numOfHistory){
double average;
double var;
int sum;
int len=numOfHistory[0].length;
for(int i=0;i<numOfHistory.length;i++) {
//求均值
average=0;
sum=0;
for(int j=0;j<len;j++) {
sum+=numOfHistory[i][j];
}
average=(double)sum/len;
//求方差
var=0;
for (int j = 0; j < len; j++)
{
var += ((double)numOfHistory[i][j] - average) * ((double)numOfHistory[i][j] - average);
}
var /= (len - 1);
//异常数据设置为0
boolean[] flag=new boolean[len];//指示变量
int noiseNum=0;
for(int j=0;j<len;j++) {//认为是正态分布
if(numOfHistory[i][j]>(average+3*Math.sqrt(var)) || numOfHistory[i][j]<(average-3*Math.sqrt(var))) { //可调参 异常数据阈值
flag[j]=true;
noiseNum++;
numOfHistory[i][j]=0;
}
}
//再求均值
average=0;
sum=0;
for(int j=0;j<len;j++) {
sum+=numOfHistory[i][j];
}
average=(double)sum/(len-noiseNum);
//异常数据赋值为均值 最好赋值为最近几天平均
for(int j=0;j<len;j++) {
if(flag[j]==true) {
int index1=j;
int index2=j;
if(j==0) {//数组第一个数是异常点
for(int k=j+1;k<len;k++) {
if(flag[k]==false)
index1=k;
}
for(int k=j+1;k<len;k++) {
if(flag[k]==false && k!=index1) {
index2=k;
}
}
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j==len-1) {//数组最后一个数是异常点
for(int k=j-1;k>=0;k--) {
if(flag[k]==false) {
index1=k;
}
}
for(int k=j;k>=0;k--) {
if(flag[k]==false && k!=index1) {
index2=k;
}
}
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else {//其他情况
if(j-1>=0 && j+1<len && flag[j-1]==false && flag[j+1]==false) {
index1=j-1;index2=j+1;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-2>=0 && j+1<len && flag[j-2]==false && flag[j+1]==false) {
index1=j-2;index2=j+1;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-1>=0 && j+2<len && flag[j-1]==false && flag[j+2]==false) {
index1=j-1;index2=j+2;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-2>=0 && j+2<len && flag[j-2]==false && flag[j+2]==false) {
index1=j-2;index2=j+2;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-1>=0 && j-2<len && flag[j-1]==false && flag[j-2]==false) {
index1=j-1;index2=j-2;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-2>=0 && j-3<len && flag[j-2]==false && flag[j-3]==false) {
index1=j-2;index2=j-3;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j+1>=0 && j+2<len && flag[j+1]==false && flag[j+2]==false) {
index1=j+1;index2=j+2;
}else if(j+2>=0 && j+3<len && flag[j+2]==false && flag[j+3]==false) {
index1=j+2;index2=j+3;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-3>=0 && j-4<len && flag[j-3]==false && flag[j-4]==false) {
index1=j-3;index2=j-4;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-2>=0 && j+3<len && flag[j-2]==false && flag[j+3]==false) {
index1=j-2;index2=j+3;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-3>=0 && j+2<len && flag[j-3]==false && flag[j+2]==false) {
index1=j-3;index2=j+2;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else if(j-3>=0 && j+3<len && flag[j-3]==false && flag[j+3]==false) {
index1=j-3;index2=j+3;
numOfHistory[i][j]=(int)Math.round((0.5*(double)(numOfHistory[i][index1]+numOfHistory[i][index2])));
}else {
numOfHistory[i][j]=(int)Math.ceil(average);
}
}
}
}


// for(int j=0;j<len;j++) {
// if(flag[j]==true)
// numOfHistory[i][j]=(int)Math.ceil(average); //ceil
// }
//如果某一天数据为0,也用均值替代 练习数据会出现虚高,因为它本来就有大量0
for(int j=0;j<len;j++) {
if(numOfHistory[i][j]==0)
numOfHistory[i][j]=(int)Math.ceil(average);
}
}
return numOfHistory;
}
// public static int[][] denoise2(int[][] numOfHistory){
// /**找到数组前三个最大值用第四个替换
// * 然后处理0数据
// */
// }
}

猜你喜欢

转载自www.cnblogs.com/wenj17/p/9243291.html