时间序列分析之 ARIMA 模型的JAVA实现

最近要用ARIMA模型预测用户的数量变化,所以调研了一下ARIMA模型,最后用JAVA实现了ARIMA算法。

一、ARIMA原理

ARIMA的原理主要参考的是ARIMA原理

二、JAVA实现

弄懂了原理,用JAVA进行了实现,主要参考的步骤是ARIMA实现步骤,JAVA代码如下

(1)AR类,用于构建AR模型

package arima;
import java.util.*;

public class AR {

	double[] stdoriginalData={};
	int p;
	ARMAMath armamath=new ARMAMath();

	/**
	 * AR模型
	 * @param stdoriginalData
	 * @param p //p为MA模型阶数
	 */
	public AR(double [] stdoriginalData,int p)
	{
		this.stdoriginalData=new double[stdoriginalData.length];
		System.arraycopy(stdoriginalData, 0, this.stdoriginalData, 0, stdoriginalData.length);
		this.p=p;
	}
/**
 * 返回AR模型参数
 * @return
 */
	public Vector<double[]> ARmodel()
	{
		Vector<double[]> v=new Vector<double[]>();
		v.add(armamath.parcorrCompute(stdoriginalData, p, 0));
		return v;//得到了自回归系数
	}

}

(2)MA类,用于构建MA模型

package arima;
import java.util.Vector;
import arima.ARMAMath;
public class MA {

	double[] stdoriginalData={};
	int q;
	ARMAMath armamath=new ARMAMath();

	/** MA模型
	 * @param stdoriginalData //预处理过后的数据
	 * @param q //q为MA模型阶数
	 */
	public MA(double [] stdoriginalData,int q)
	{
		this.stdoriginalData=new double[stdoriginalData.length];
		System.arraycopy(stdoriginalData, 0, this.stdoriginalData, 0, stdoriginalData.length);
		this.q=q;

	}
/**
 * 返回MA模型参数
 * @return
 */
	public Vector<double[]> MAmodel()
	{
		Vector<double[]> v=new Vector<double[]>();
		v.add(armamath.getMApara(armamath.autocorGrma(stdoriginalData,q), q));

		return v;//拿到MA模型里面的参数值
	}

}

(3)ARMA类,用于构建ARMA模型

package arima;
import java.util.*;

public class ARMA {

	double[] stdoriginalData={};
	int p;
	int q;
	ARMAMath armamath=new ARMAMath();

	/**
	 * ARMA模型
	 * @param stdoriginalData
	 * @param p,q //p,q为MA模型阶数
	 */
	public ARMA(double [] stdoriginalData,int p,int q)
	{
		this.stdoriginalData=new double[stdoriginalData.length];
		System.arraycopy(stdoriginalData, 0, this.stdoriginalData, 0, stdoriginalData.length);
		this.p=p;
		this.q=q;
	}
	public Vector<double[]> ARMAmodel()
	{
		double[] arcoe=armamath.parcorrCompute(stdoriginalData, p, q);
		double[] autocorData=getautocorofMA(p, q, stdoriginalData, arcoe);
		double[] macoe=armamath.getMApara(autocorData, q);//得到MA模型里面的参数值
		Vector<double[]> v=new Vector<double[]>();
		v.add(arcoe);
		v.add(macoe);
		return v;
	}
	/**
	 * 得到MA的自相关系数
	 * @param p
	 * @param q
	 * @param stdoriginalData
	 * @param autoCordata
	 * @return
	 */
	public double[] getautocorofMA(int p,int q,double[] stdoriginalData,double[] autoRegress)
	{
		int temp=0;
		double[] errArray=new double[stdoriginalData.length-p];
		int count=0;
		for(int i=p;i<stdoriginalData.length;i++)
		{
			temp=0;
			for(int j=1;j<=p;j++)
				temp+=stdoriginalData[i-j]*autoRegress[j-1];
			errArray[count++]=stdoriginalData[i]-temp;//保存估计残差序列
		}
		return armamath.autocorGrma(errArray, q);
	}
}

(4)ARIMA类,用于构建ARIMA模型

package arima;
import arima.ARMAMath;
import java.util.*;

public class ARIMA {

	double[] originalData={};
	double[] originalDatafirDif={};
	double[] originalDatasecDif={};
	double[] originalDatathiDif={};
	double[] originalDataforDif={};
	double[] originalDatafriDif={};

	ARMAMath armamath=new ARMAMath();
	double stderrDara=0;
	double avgsumData=0;
	Vector<double[]> armaARMAcoe=new Vector<double[]>();
	Vector<double[]> bestarmaARMAcoe=new Vector<double[]>();
	int typeofPredeal=0;
/**
 * 构造函数
 * @param originalData 原始时间序列数据
 */
	public ARIMA(double [] originalData,int typeofPredeal)
	{
		this.originalData=originalData;
		this.typeofPredeal=typeofPredeal;//数据预处理类型 1:一阶普通查分7:季节性差分
	}
/**
 * 原始数据标准化处理:一阶季节性差分
 * @return 差分过后的数据
 */
	public double[] preDealDif(double[] originalData)
	{
		//seasonal Difference:Peroid=7
		double []tempData=new double[originalData.length-7];
		for(int i=0;i<originalData.length-7;i++)
		{
			tempData[i]=originalData[i+7]-originalData[i];
		}
		return tempData;
	}

/**
 *
 */
	public double[] preFirDif(double[] originalData)
	{
		// Difference:Peroid=1
		double []tempData=new double[originalData.length-1];
		for(int i=0;i<originalData.length-1;i++)
		{
			tempData[i]=originalData[i+1]-originalData[i];
		}

		return tempData;
	}

/**
 * 原始数据标准化处理:Z-Score归一化
 * @param 待处理数据
 * @return 归一化过后的数据
 */
	public double[] preDealNor(double[] tempData)
	{
		//Z-Score
		avgsumData=armamath.avgData(tempData);
		stderrDara=armamath.stderrData(tempData);

		for(int i=0;i<tempData.length;i++)
		{
			tempData[i]=(tempData[i]-avgsumData)/stderrDara;
		}
		return tempData;
	}

	public modelandpara getARIMAmodel(int[] bestmodel)
	{
		double[] stdoriginalData=null;

		if(typeofPredeal==0)
			{
				stdoriginalData=new double[originalData.length];
				System.arraycopy(originalData, 0, stdoriginalData, 0,originalData.length);
			}
		else if(typeofPredeal==1)		//原始数据一阶普通差分处理
			{
				originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
				System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

				stdoriginalData=new double[originalDatafirDif.length];
				System.arraycopy(originalDatafirDif, 0, stdoriginalData, 0,originalDatafirDif.length);
			}
		else if (typeofPredeal==2)
			{
				originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
				System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

				originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
				System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

				stdoriginalData=new double[originalDatasecDif.length];
				System.arraycopy(originalDatasecDif, 0, stdoriginalData, 0,originalDatasecDif.length);
			}
		else if(typeofPredeal==3)
			{
				originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
				System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

				originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
				System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

				originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
				System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

				stdoriginalData=new double[originalDatathiDif.length];
				System.arraycopy(originalDatathiDif, 0, stdoriginalData, 0,originalDatathiDif.length);	

			}
		else if(typeofPredeal==4)
			{

				originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
				System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

				originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
				System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

				originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
				System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

				originalDataforDif=new double[this.preFirDif(originalDatathiDif).length];
				System.arraycopy(this.preFirDif(originalDatathiDif), 0, originalDataforDif, 0,originalDataforDif.length);	

				stdoriginalData=new double[originalDataforDif.length];
				System.arraycopy(originalDataforDif, 0, stdoriginalData, 0,originalDataforDif.length);	

			}
		else if(typeofPredeal==5)
			{
				originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
				System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

				originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
				System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

				originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
				System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

				originalDataforDif=new double[this.preFirDif(originalDatathiDif).length];
				System.arraycopy(this.preFirDif(originalDatathiDif), 0, originalDataforDif, 0,originalDataforDif.length);	

				originalDatafriDif=new double[this.preFirDif(originalDataforDif).length];
				System.arraycopy(this.preFirDif(originalDataforDif), 0, originalDatafriDif, 0,originalDatafriDif.length);	

				stdoriginalData=new double[originalDatafriDif.length];
				System.arraycopy(originalDatafriDif, 0, stdoriginalData, 0,originalDatafriDif.length);	

			}
		else//原始数据季节性差分处理
			{
				stdoriginalData=new double[this.preDealDif(originalData).length];
				System.arraycopy(this.preDealDif(originalData), 0, stdoriginalData, 0,this.preDealDif(originalData).length);
			}

		armaARMAcoe.clear();
		bestarmaARMAcoe.clear();

		if(bestmodel[0]==0)
		{
			MA ma=new MA(stdoriginalData, bestmodel[1]);
			armaARMAcoe=ma.MAmodel(); //拿到ma模型的参数

		}
		else if(bestmodel[1]==0)
		{
			AR ar=new AR(stdoriginalData, bestmodel[0]);
			armaARMAcoe=ar.ARmodel(); //拿到ar模型的参数

		}
		else
		{
			ARMA arma=new ARMA(stdoriginalData, bestmodel[0], bestmodel[1]);
			armaARMAcoe=arma.ARMAmodel();//拿到arma模型的参数

		}

		bestarmaARMAcoe=armaARMAcoe;
		modelandpara mp=new modelandpara(bestmodel, bestarmaARMAcoe);

		return mp;
 	}
/**
* 得到ARMA模型=[p,q]
 * @return ARMA模型的阶数信息
 *//*
	public modelandpara getARIMAmodel()
	{
		double[] stdoriginalData=null;
		if(typeofPredeal==0)
		{
			stdoriginalData=new double[originalData.length];
			System.arraycopy(originalData, 0, stdoriginalData, 0,originalData.length);
		}
	else if(typeofPredeal==1)		//原始数据一阶普通差分处理
		{

			originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
			System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

			stdoriginalData=new double[originalDatafirDif.length];
			System.arraycopy(originalDatafirDif, 0, stdoriginalData, 0,originalDatafirDif.length);
		}
	else if (typeofPredeal==2)
		{
			originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
			System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

			originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
			System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

			stdoriginalData=new double[originalDatasecDif.length];
			System.arraycopy(originalDatasecDif, 0, stdoriginalData, 0,originalDatasecDif.length);
		}
	else if(typeofPredeal==3)
		{
			originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
			System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

			originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
			System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

			originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
			System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

			stdoriginalData=new double[originalDatathiDif.length];
			System.arraycopy(originalDatathiDif, 0, stdoriginalData, 0,originalDatathiDif.length);	

		}
	else if(typeofPredeal==4)
		{
			originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
			System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

			originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
			System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

			originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
			System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

			originalDataforDif=new double[this.preFirDif(originalDatathiDif).length];
			System.arraycopy(this.preFirDif(originalDatathiDif), 0, originalDataforDif, 0,originalDataforDif.length);	

			stdoriginalData=new double[originalDataforDif.length];
			System.arraycopy(originalDataforDif, 0, stdoriginalData, 0,originalDataforDif.length);	

		}
	else if(typeofPredeal==5)
		{
			originalDatafirDif=new double[this.preFirDif(originalData).length];//原始数据一阶普通差分处理
			System.arraycopy(this.preFirDif(originalData), 0, originalDatafirDif, 0,originalDatafirDif.length);	

			originalDatasecDif=new double[this.preFirDif(originalDatafirDif).length];
			System.arraycopy(this.preFirDif(originalDatafirDif), 0, originalDatasecDif, 0,originalDatasecDif.length);	

			originalDatathiDif=new double[this.preFirDif(originalDatasecDif).length];
			System.arraycopy(this.preFirDif(originalDatasecDif), 0, originalDatathiDif, 0,originalDatathiDif.length);	

			originalDataforDif=new double[this.preFirDif(originalDatathiDif).length];
			System.arraycopy(this.preFirDif(originalDatathiDif), 0, originalDataforDif, 0,originalDataforDif.length);	

			originalDatafriDif=new double[this.preFirDif(originalDataforDif).length];
			System.arraycopy(this.preFirDif(originalDataforDif), 0, originalDatafriDif, 0,originalDatafriDif.length);	

			stdoriginalData=new double[this.preFirDif(originalDatafriDif).length];
			System.arraycopy(this.preFirDif(originalDatafriDif), 0, stdoriginalData, 0,originalDatafriDif.length);	

		}
	else//原始数据季节性差分处理
		{
			stdoriginalData=new double[this.preDealDif(originalData).length];
			System.arraycopy(this.preDealDif(originalData), 0, stdoriginalData, 0,this.preDealDif(originalData).length);
		}

		int paraType=0;
		double minAIC=9999999;
		int bestModelindex=0;
		int[][] model=new int[][]{{0,1},{1,0},{1,1},{0,2},{2,0},{2,2},{1,2},{2,1},{3,0},{0,3},{3,1},{1,3},{3,2},{2,3},{3,3}};
		//对模型进行迭代,选出平均预测误差最小的模型作为我们的模型
		for(int i=0;i<model.length;i++)
		{

			if(model[i][0]==0)
			{
				MA ma=new MA(stdoriginalData, model[i][1]);
				armaARMAcoe=ma.MAmodel(); //拿到ma模型的参数
				paraType=1;
			}
			else if(model[i][1]==0)
			{
				AR ar=new AR(stdoriginalData, model[i][0]);
				armaARMAcoe=ar.ARmodel(); //拿到ar模型的参数
				paraType=2;
			}
			else
			{
				ARMA arma=new ARMA(stdoriginalData, model[i][0], model[i][1]);
				armaARMAcoe=arma.ARMAmodel();//拿到arma模型的参数
				paraType=3;
			}

			double temp=getmodelAIC(armaARMAcoe,stdoriginalData,paraType);
			if (temp<minAIC)
			{
				bestModelindex=i;
				minAIC=temp;
				bestarmaARMAcoe=armaARMAcoe;
			}
		}

		modelandpara mp=new modelandpara(model[bestModelindex], bestarmaARMAcoe);

		return mp;
 	}*/
/**
 * 计算ARMA模型的AIC
 * @param para 装载模型的参数信息
 * @param stdoriginalData   预处理过后的原始数据
 * @param type 1:MA;2:AR;3:ARMA
 * @return 模型的AIC值
 */
	public double getmodelAIC(Vector<double[]> para,double[] stdoriginalData,int type)
	{
		double temp=0;
		double temp2=0;
		double sumerr=0;
		int p=0;//ar1,ar2,...,sig2
		int q=0;//sig2,ma1,ma2...
		int n=stdoriginalData.length;
		Random random=new Random();

		if(type==1)
		{
			double[] maPara=new double[para.get(0).length];
			System.arraycopy(para.get(0), 0, maPara, 0, para.get(0).length);

			q=maPara.length;
			double[] err=new double[q];  //error(t),error(t-1),error(t-2)...
			for(int k=q-1;k<n;k++)
			{
				temp=0;

				for(int i=1;i<q;i++)
				{
					temp+=maPara[i]*err[i];
				}

				//产生各个时刻的噪声
				for(int j=q-1;j>0;j--)
				{
					err[j]=err[j-1];
				}
				err[0]=random.nextGaussian()*Math.sqrt(maPara[0]);

				//估计的方差之和
				sumerr+=(stdoriginalData[k]-(temp))*(stdoriginalData[k]-(temp));

			}

			//return  (n-(q-1))*Math.log(sumerr/(n-(q-1)))+(q)*Math.log(n-(q-1));//AIC 最小二乘估计
			return (n-(q-1))*Math.log(sumerr/(n-(q-1)))+(q+1)*2;
		}
		else if(type==2)
		{
			double[] arPara=new double[para.get(0).length];
			System.arraycopy(para.get(0), 0, arPara, 0, para.get(0).length);

			p=arPara.length;
			for(int k=p-1;k<n;k++)
			{
				temp=0;
				for(int i=0;i<p-1;i++)
				{
					temp+=arPara[i]*stdoriginalData[k-i-1];
				}
				//估计的方差之和
				sumerr+=(stdoriginalData[k]-temp)*(stdoriginalData[k]-temp);
			}

			return (n-(q-1))*Math.log(sumerr/(n-(q-1)))+(p+1)*2;
			//return (n-(p-1))*Math.log(sumerr/(n-(p-1)))+(p)*Math.log(n-(p-1));//AIC 最小二乘估计
		}
		else
		{
			double[] arPara=new double[para.get(0).length];
			System.arraycopy(para.get(0), 0, arPara, 0, para.get(0).length);
			double[] maPara=new double[para.get(1).length];
			System.arraycopy(para.get(1), 0, maPara, 0, para.get(1).length);

			p=arPara.length;
			q=maPara.length;
			double[] err=new double[q];  //error(t),error(t-1),error(t-2)...

			for(int k=p-1;k<n;k++)
			{
				temp=0;
				temp2=0;
				for(int i=0;i<p-1;i++)
				{
					temp+=arPara[i]*stdoriginalData[k-i-1];
				}

				for(int i=1;i<q;i++)
				{
					temp2+=maPara[i]*err[i];
				}

				//产生各个时刻的噪声
				for(int j=q-1;j>0;j--)
				{
					err[j]=err[j-1];
				}
				//System.out.println("predictBeforeDiff="+1);
				err[0]=random.nextGaussian()*Math.sqrt(maPara[0]);
				//估计的方差之和
				sumerr+=(stdoriginalData[k]-(temp2+temp))*(stdoriginalData[k]-(temp2+temp));
			}

			return (n-(q-1))*Math.log(sumerr/(n-(q-1)))+(p+q)*2;
			//return (n-(p-1))*Math.log(sumerr/(n-(p-1)))+(p+q-1)*Math.log(n-(p-1));//AIC 最小二乘估计
		}
	}
/**
 * 对预测值进行反差分处理
 * @param predictValue 预测的值
 * @return 反差分过后的预测值
 */
	public int aftDeal(int predictValue)
	{
		int temp=0;
		//System.out.println("predictBeforeDiff="+predictValue);
		if(typeofPredeal==0)
			temp=((int)predictValue);
		else if(typeofPredeal==1)
			temp=(int)(predictValue+originalData[originalData.length-1]);
		else if(typeofPredeal==2)
			temp=(int)(predictValue+originalDatafirDif[originalDatafirDif.length-1]+originalData[originalData.length-1]);
		else if(typeofPredeal==3)
			temp=(int)(predictValue+originalDatasecDif[originalDatasecDif.length-1]+originalDatafirDif[originalDatafirDif.length-1]+originalData[originalData.length-1]);
		else if(typeofPredeal==4)
			temp=(int)(predictValue+originalDatathiDif[originalDatathiDif.length-1]+originalDatasecDif[originalDatasecDif.length-1]+originalDatafirDif[originalDatafirDif.length-1]+originalData[originalData.length-1]);
		else if(typeofPredeal==5)
			temp=(int)(predictValue+originalDataforDif[originalDataforDif.length-1]+originalDatathiDif[originalDatathiDif.length-1]+originalDatasecDif[originalDatasecDif.length-1]+originalDatafirDif[originalDatafirDif.length-1]+originalData[originalData.length-1]);
		else
			temp=(int)(predictValue+originalData[originalData.length-7]);	

				return temp>0?temp:0;
	}

/**
 * 进行一步预测
 * @param p ARMA模型的AR的阶数
 * @param q ARMA模型的MA的阶数
 * @return 预测值
 */
	public int predictValue(int p,int q,Vector<double[]> bestpara)
	{
		double[] stdoriginalData=null;
		if (typeofPredeal==0)
			{
				stdoriginalData=new double[originalData.length];
				System.arraycopy(originalData, 0, stdoriginalData, 0, originalData.length);

			}
		else if(typeofPredeal==1)
			{
				stdoriginalData=new double[originalDatafirDif.length];

				System.arraycopy(originalDatafirDif, 0, stdoriginalData, 0, originalDatafirDif.length);
			}
		else if(typeofPredeal==2)
			{
				stdoriginalData=new double[originalDatasecDif.length];//普通二阶差分处理
				System.arraycopy(originalDatasecDif, 0, stdoriginalData, 0, originalDatasecDif.length);
			}

		else if(typeofPredeal==3)
			{
				stdoriginalData=new double[originalDatathiDif.length];//普通三阶差分处理
				System.arraycopy(originalDatathiDif, 0, stdoriginalData, 0, originalDatathiDif.length);
			}

		else if(typeofPredeal==4)
			{
				stdoriginalData=new double[originalDataforDif.length];//普通四阶差分处理
				System.arraycopy(originalDataforDif, 0, stdoriginalData, 0, originalDataforDif.length);
			}

		else if(typeofPredeal==5)
			{
				stdoriginalData=new double[originalDatafriDif.length];//普通五阶差分处理
				System.arraycopy(originalDatafriDif, 0, stdoriginalData, 0, originalDatafriDif.length);
			}
		else
			{
				stdoriginalData=new double[this.preDealDif(originalData).length];//季节性一阶差分
				System.arraycopy(this.preDealDif(originalData), 0, stdoriginalData, 0, this.preDealDif(originalData).length);
			}
		//System.out.println("typeofPredeal= "+typeofPredeal+typeofPredeal);

//		for(int i=0;i<originalDatafirDif.length;i++)
//			System.out.println(originalDatafirDif[i]);
//
		int predict=0;
		int n=stdoriginalData.length;
		double temp=0,temp2=0;
		double[] err=new double[q+1];

		Random random=new Random();
		if(p==0)
		{
			double[] maPara=bestpara.get(0);

			for(int k=q;k<n;k++)
			{
				temp=0;
				for(int i=1;i<=q;i++)
				{
					temp+=maPara[i]*err[i];
				}
				//产生各个时刻的噪声
				for(int j=q;j>0;j--)
				{
					err[j]=err[j-1];
				}
				err[0]=random.nextGaussian()*Math.sqrt(maPara[0]);
			}
			predict=(int)(temp); //产生预测
			//System.out.println("predict=q "+predict);
		}
		else if(q==0)
		{
			double[] arPara=bestpara.get(0);

			for(int k=p;k<n;k++)
			{
				temp=0;
				for(int i=0;i<p;i++)
				{
					temp+=arPara[i]*stdoriginalData[k-i-1];
				}
			}
			predict=(int)(temp);
			//System.out.println("predict= p"+predict);
		}
		else
		{
			double[] arPara=bestpara.get(0);
			double[] maPara=bestpara.get(1);

			err=new double[q+1];  //error(t),error(t-1),error(t-2)...
			for(int k=p;k<n;k++)
			{
				temp=0;
				temp2=0;
				for(int i=0;i<p;i++)
				{
					temp+=arPara[i]*stdoriginalData[k-i-1];
				}

				for(int i=1;i<=q;i++)
				{
					temp2+=maPara[i]*err[i];
				}

				//产生各个时刻的噪声
				for(int j=q;j>0;j--)
				{
					err[j]=err[j-1];
				}

				err[0]=random.nextGaussian()*Math.sqrt(maPara[0]);
			}

			predict=(int)(temp2+temp);
			//System.out.println("predict=p,q "+predict);
		}
		return predict;
	}

}

class modelandpara
{
	int[] model;
	Vector<double[]> para;
	public modelandpara(int[] model,Vector<double[]> para)
	{
		this.model=model;
		this.para=para;
	}
}

(5)ARIMAiFlex类,用于构建AR模型

package arima;
import java.util.Hashtable;
import java.util.*;

public class ARIMAiFlex {

	int             count=0;
	int []          model=new int[2];
	int[][]      modelOri=new int[][]{{0,1},{1,0},{1,1},{0,2},{2,0},{2,2},{1,2},{2,1},{3,0},{0,3},{3,1},{1,3},{3,2},{2,3},{3,3}};

	modelandpara       mp=null;
	int  predictValuetemp=0;
	int   avgpredictValue=0;
	int[]       bestmodel=new int[2];
	double[][] predictErr=new double[7][modelOri.length];
	double  minpreDicterr=9999999;
	int  bestpreDictValue=0;
	int           bestDif=0;
	int            memory=10;
	double[] traindataArray=null;
	double         validate=0;
	double[]   predataArray=null;

	double[]     dataArrayPredict=null;
	Hashtable<String,Integer>  ht=new Hashtable<String,Integer>();
	Hashtable<String,Integer> ht2=new Hashtable<String,Integer>();

	double thresvalue=0;

	public ARIMAiFlex(double []dataArray)
	{
		//模型训练
		System.out.println("begin to train...");
		Vector<int[]> trainResult=this.Train(dataArray);
		//预测数据初始化
		int tempPredict=0;
		System.out.println("begin to predict...");
		for(int i=0;i<trainResult.size();i++)
		{
			thresvalue=0;
			System.out.println("predict..."+i+"/"+trainResult.size());
			tempPredict+=this.Predict(dataArray,memory,trainResult.get(i),0);
		}
		tempPredict=tempPredict/trainResult.size();
		System.out.println("tempPredict="+tempPredict);
	}

	public void preData(double[] dataArray,int type,int memory)
	{
			//      ++
		//**********
		 //**********
		this.traindataArray=new double[dataArray.length-memory];
		System.arraycopy(dataArray, type, traindataArray, 0, traindataArray.length);
		this.validate=dataArray[traindataArray.length+type];//最后一个值作为训练时候的验证值。

	}

	public int Predict(double[] dataArray,int memory,int[] trainResult,double fanwei)
	{
		if(memory<0)
			return (int)(dataArray[dataArray.length-1]+dataArray[dataArray.length-2])/2;

		this.predataArray=new double[dataArray.length-memory];
		System.arraycopy(dataArray, memory, predataArray, 0, predataArray.length);
		ARIMA arima=new ARIMA(predataArray,trainResult[0]); //对原始数据做几阶差分处理0,1,2,7
		//参数初始化
		int count=100;
		int predictValuetemp=0;

		//统计每种模型的预测平均值
		while(count-->0)
		{
			mp=arima.getARIMAmodel(modelOri[trainResult[1]]);
			predictValuetemp+=arima.aftDeal(arima.predictValue(mp.model[0],mp.model[1],mp.para));
		}

		predictValuetemp/=100;
		//System.out.println("Predict value is:"+predictValuetemp);

		if(Math.abs(predictValuetemp-predataArray[predataArray.length-1])/predataArray[predataArray.length-1]>(0.3+fanwei))
		{
			thresvalue++;
			System.out.println("thresvalue="+thresvalue);
			//重新训练和预测
			//模型训练
			Vector<int[]> trainResult2=this.Train(dataArray);
			//预测数据初始化
			int tempPredict=0;
			for(int i=0;i<trainResult2.size();i++)
			{
				tempPredict+=this.Predict(dataArray,(memory-5),trainResult2.get(i),0.1*thresvalue);
			}
			tempPredict=tempPredict/trainResult2.size();
			//System.out.println("tempPredict="+tempPredict);
			return tempPredict;
		}
		else
		{
			return predictValuetemp;
		}
	}

	public Vector<int[]> Train(double[] dataArray)
	{
		int memory=60;//训练的时候预测的值的个数

		for(int datai=0;datai<memory;datai++)
		{
			//System.out.println("train... "+datai+"/"+memory);
			this.preData(dataArray, datai,memory);//准备训练数据

			for(int diedai=0;diedai<7;diedai++)
			{
				ARIMA arima=new ARIMA(traindataArray,diedai); //对原始数据做几阶差分处理0,1,2,7

				//统计每种模型的预测平均值
				for(int modeli=0;modeli<modelOri.length;modeli++)
				{
					//参数初始化
					count=100;
					predictValuetemp=0;

					while(count-->0)
					{
						mp=arima.getARIMAmodel(modelOri[modeli]);
						predictValuetemp+=arima.aftDeal(arima.predictValue(mp.model[0],mp.model[1],mp.para));
						//System.out.println("predictValuetemp"+predictValuetemp);
					}
					predictValuetemp/=100;
					//计算训练误差
					predictErr[diedai][modeli]+=Math.abs(100*(predictValuetemp-validate)/validate);
				}
			}
		}

		double minvalue=10000000;
		int tempi=0;
		int tempj=0;
		Vector<int[]> bestmodelVector=new Vector<int[]>();
		int[][] flag=new int[7][modelOri.length];

		for(int ii=0;ii<5;ii++)
		{	minvalue=10000000;
			for(int i=0;i<predictErr.length;i++)
			 {
				for(int j=0;j<predictErr[i].length;j++)
					{
						if(flag[i][j]==0)
						{
							if(predictErr[i][j]<minvalue)
							{
								minvalue=predictErr[i][j];
								tempi=i;
								tempj=j;
								flag[i][j]=1;
							}
						}
					}
			}
			bestmodelVector.add(new int[]{tempi,tempj});

			//System.out.println("best model:Dif="+tempi+"..."+"index of model="+tempj);
			System.out.println("ARIMAAvgPredictErr="+minvalue/memory);
		}

//		for(int i=0;i<predictErr.length;i++)
//			for(int j=0;j<predictErr[i].length;j++)
//			{
//				System.out.println("Dif "+i+" Model index"+j+"= "+predictErr[i][j]/memory);
//			}

		//System.out.println("--tempi="+tempi+"~~~"+"tempj="+tempj);
		System.out.println("----------------------------------------");

		return bestmodelVector;
	}	

	}

(6)ARMAMath类,常见的数据计算任务

package arima;
import Jama.Matrix;

public class ARMAMath
{
	public double avgData(double[] dataArray)
	{
		return this.sumData(dataArray)/dataArray.length;
	}

	public double sumData(double[] dataArray)
	{
		double sumData=0;
		for(int i=0;i<dataArray.length;i++)
		{
			sumData+=dataArray[i];
		}
		return sumData;
	}

	public double stderrData(double[] dataArray)
	{
		return Math.sqrt(this.varerrData(dataArray));
	}

	public double varerrData(double[] dataArray)
	{
		double variance=0;
		double avgsumData=this.avgData(dataArray);

		for(int i=0;i<dataArray.length;i++)
		{
			dataArray[i]-=avgsumData;
			variance+=dataArray[i]*dataArray[i];
		}
		return variance/dataArray.length;//variance error;
	}

	/**
	 * 计算自相关的函数 Tho(k)=Grma(k)/Grma(0)
	 * @param dataArray 数列
	 * @param order 阶数
	 * @return
	 */
	public double[] autocorData(double[] dataArray,int order)
	{
		double[] autoCor=new double[order+1];
		double varData=this.varerrData(dataArray);//标准化过后的方差

		for(int i=0;i<=order;i++)
		{
			autoCor[i]=0;
			for(int j=0;j<dataArray.length-i;j++)
			{
				autoCor[i]+=dataArray[j+i]*dataArray[j];
			}
			autoCor[i]/=(dataArray.length-i);
			autoCor[i]/=varData;
		}
		return autoCor;
	}

/**
 * Grma
 * @param dataArray
 * @param order
 * @return 序列的自相关系数
 */
	public double[] autocorGrma(double[] dataArray,int order)
	{
		double[] autoCor=new double[order+1];
		for(int i=0;i<=order;i++)
		{
			autoCor[i]=0;
			for(int j=0;j<dataArray.length-i;j++)
			{
				autoCor[i]+=dataArray[j+i]*dataArray[j];
			}
			autoCor[i]/=(dataArray.length-i);

		}
		return autoCor;
	}

/**
 * 求偏自相关系数
 * @param dataArray
 * @param order
 * @return
 */
	public double[] parautocorData(double[] dataArray,int order)
	{
		double parautocor[]=new double[order];

		for(int i=1;i<=order;i++)
	    {
			parautocor[i-1]=this.parcorrCompute(dataArray, i,0)[i-1];
	    }
		return parautocor;
	}
/**
 * 产生Toplize矩阵
 * @param dataArray
 * @param order
 * @return
 */
	public double[][] toplize(double[] dataArray,int order)
	{//返回toplize二维数组
		double[][] toplizeMatrix=new double[order][order];
		double[] atuocorr=this.autocorData(dataArray,order);

		for(int i=1;i<=order;i++)
		{
			int k=1;
			for(int j=i-1;j>0;j--)
			{
				toplizeMatrix[i-1][j-1]=atuocorr[k++];
			}
			toplizeMatrix[i-1][i-1]=1;
			int kk=1;
			for(int j=i;j<order;j++)
			{
				toplizeMatrix[i-1][j]=atuocorr[kk++];
			}
		}
		return toplizeMatrix;
	}

	/**
	 * 解MA模型的参数
	 * @param autocorData
	 * @param q
	 * @return
	 */
	public double[] getMApara(double[] autocorData,int q)
	{
		double[] maPara=new double[q+1];//第一个存放噪声参数,后面q个存放ma参数sigma2,ma1,ma2...
		double[] tempmaPara=new double[q+1];

		double temp=0;
		boolean iterationFlag=true;
		//解方程组
		//迭代法解方程组
		maPara[0]=1;//初始化
		int count=10000;
		while(iterationFlag&&count-->0)
		{
			temp=0;
			for(int i=1;i<maPara.length;i++)
			{
				temp+=maPara[i]*maPara[i];
			}
			tempmaPara[0]=autocorData[0]/(1+temp);

			for(int i=1;i<maPara.length;i++)
			{
				temp=0;
				for(int j=1;j<maPara.length-i;j++)
				{
					temp+=maPara[j]*maPara[j+i];
				}
				tempmaPara[i]=-(autocorData[i]/tempmaPara[0]-temp);
			}
			iterationFlag=false;
			for(int i=0;i<maPara.length;i++)
			{
				if(Math.abs(maPara[i]-tempmaPara[i])>0.00001)
				{
					iterationFlag=true;
					break;
				}
			}

			System.arraycopy(tempmaPara, 0, maPara, 0, tempmaPara.length);
		}

		return maPara;
	}
	/**
	 * 计算自回归系数
	 * @param dataArray
	 * @param p
	 * @param q
	 * @return
	 */
	public double[] parcorrCompute(double[] dataArray,int p,int q)
	{
		double[][] toplizeArray=new double[p][p];//p阶toplize矩阵;

		double[] atuocorr=this.autocorData(dataArray,p+q);//返回p+q阶的自相关函数
		double[] autocorrF=this.autocorGrma(dataArray, p+q);//返回p+q阶的自相关系数数
		for(int i=1;i<=p;i++)
		{
			int k=1;
			for(int j=i-1;j>0;j--)
			{
				toplizeArray[i-1][j-1]=atuocorr[q+k++];
			}
			toplizeArray[i-1][i-1]=atuocorr[q];
			int kk=1;
			for(int j=i;j<p;j++)
			{
				toplizeArray[i-1][j]=atuocorr[q+kk++];
			}
		}

	    Matrix toplizeMatrix = new Matrix(toplizeArray);//由二位数组转换成二维矩阵
	    Matrix toplizeMatrixinverse=toplizeMatrix.inverse();//矩阵求逆运算

	    double[] temp=new double[p];
	    for(int i=1;i<=p;i++)
	    {
	    	temp[i-1]=atuocorr[q+i];
	    }

		Matrix autocorrMatrix=new Matrix(temp, p);
		Matrix parautocorDataMatrix=toplizeMatrixinverse.times(autocorrMatrix); //  [Fi]=[toplize]x[autocorr]';
		//矩阵计算结果应该是按照[a b c]'  列向量存储的
		//System.out.println("row="+parautocorDataMatrix.getRowDimension()+"  Col="+parautocorDataMatrix.getColumnDimension());
		//parautocorDataMatrix.print(p, 2);//(输出几行,小数点后保留位数)
		//System.out.println(parautocorDataMatrix.get(p-1,0));

		double[] result=new double[parautocorDataMatrix.getRowDimension()+1];
		for(int i=0;i<parautocorDataMatrix.getRowDimension();i++)
		{
			result[i]=parautocorDataMatrix.get(i,0);
		}

		//估算sigmat2
		double sum2=0;
		for(int i=0;i<p;i++)
			for(int j=0;j<p;j++)
			{
				sum2+=result[i]*result[j]*autocorrF[Math.abs(i-j)];
			}
		result[result.length-1]=autocorrF[0]-sum2; //result数组最后一个存储干扰估计值

			return result;   //返回0列的最后一个就是k阶的偏自相关系数 pcorr[k]=返回值
	}

	}

(7)test1,用于导入数据进行测试


package arima;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class test1 {

	public static void main(String args[])
	{
		Scanner ino=null;

		try {
			/*********************************************************/
			ArrayList<Double> arraylist=new ArrayList<Double>();
			ino=new Scanner(new File("E:\\work\\Arima\\Arima\\Data\\ceshidata.txt"));

			while(ino.hasNext())
			{
				arraylist.add(Double.parseDouble(ino.next()));
			}

			double[] dataArray=new double[arraylist.size()]; 

			for(int i=0;i<dataArray.length;i++)
				dataArray[i]=arraylist.get(i);

			ARIMAiFlex myarima=new ARIMAiFlex(dataArray);
			currentAlgorithm cc=new currentAlgorithm(dataArray);

			/*********************************************************/

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			ino.close();
		}
	}

}
时间: 2024-11-12 10:13:49

时间序列分析之 ARIMA 模型的JAVA实现的相关文章

【R实践】时间序列分析之ARIMA模型预测___R篇

时间序列分析之ARIMA模型预测__R篇 之前一直用SAS做ARIMA模型预测,今天尝试用了一下R,发现灵活度更高,结果输出也更直观.现在记录一下如何用R分析ARIMA模型. 1. 处理数据 1.1. 导入forecast包 forecast包是一个封装的ARIMA统计软件包,在默认情况下,R没有预装forecast包,因此需要先安装该包 > install.packages("forecast') 导入依赖包zoo,再导入forecast包 > library("zoo&

金融时间序列分析:11.模型分析小结

凹号 检列 卉葳 ⒖隹 来 湛 症凉 é 汶ま 绚袼  娩率 躬甍 硅擗 壳逮 块吻 绯欧 渖 笄 禀笼 熬i 沔玳 盖 敷比 具с 殚禄 脐位 匈焰 迥哔 恫 坻摁 鱿瑞 懒 鲥撇 ┭I  洼节 誉辋 杠锅 ╂ 捃 佣谯 怪 矢沓 X慎 饶讽 执 吖 缃鲈 色娲 饯埠 致 果侗 祛 桥 迫鳔 侵仃 圹扛 熠烷 诈惺 殷侠 态 戌 确 沓 Ⅴ滚 篆鸣 元隋 棚蚧 侧浞 炕 嫣戒 督捐 Π心 栳旰 ョ责 缆骺 醍锏 滁 谪契 ○ 喹 椎皙 砑

从入门谈起,ARIMA如何应用到时间序列分析中?

Table of Contents 1. 基础概念 1.1. 时间序列的平稳性(弱平稳) 1.1.1. 定义 1.1.2. 平稳性检验 1.1.3. 如何让时间序列变平稳 1.2. 随机游走 1.2.1. 定义 1.2.2. 不平稳性的证明 1.3. ACF 1.4. PACF 2. ARIMA 模型 2.1. 介绍 2.1.1. AR模型 2.1.2. MA模型 2.1.3. 差分项 2.2. ARIMA模型调参指南 2.2.1. d: 差分阶数选取 2.2.2. p: AR模型参数的选取 2

时间序列分析工具箱—— h2o + timetk

目录 时间序列分析工具箱-- h2o + timetk h2o 的用途 加载包 安装 h2o 加载包 数据 教程:h2o + timetk,时间序列机器学习 时间序列机器学习 最终的胜利者是... 翻译自<Demo Week: Time Series Machine Learning with h2o and timetk> 原文链接:https://www.business-science.io/code-tools/2017/10/28/demo_week_h2o.html 文字和代码略有

时间序列分析算法【R详解】

简介 在商业应用中,时间是最重要的因素,能够提升成功率.然而绝大多数公司很难跟上时间的脚步.但是随着技术的发展,出现了很多有效的方法,能够让我们预测未来.不要担心,本文并不会讨论时间机器,讨论的都是很实用的东西. 本文将要讨论关于预测的方法.有一种预测是跟时间相关的,而这种处理与时间相关数据的方法叫做时间序列模型.这个模型能够在与时间相关的数据中,寻到一些隐藏的信息来辅助决策. 当我们处理时序序列数据的时候,时间序列模型是非常有用的模型.大多数公司都是基于时间序列数据来分析第二年的销售量,网站流

【机器学习笔记之五】用ARIMA模型做需求预测用ARIMA模型做需求预测

本文结构: 时间序列分析? 什么是ARIMA? ARIMA数学模型? input,output 是什么? 怎么用?-代码实例 常见问题? 时间序列分析? 时间序列,就是按时间顺序排列的,随时间变化的数据序列.生活中各领域各行业太多时间序列的数据了,销售额,顾客数,访问量,股价,油价,GDP,气温... 随机过程的特征有均值.方差.协方差等.如果随机过程的特征随着时间变化,则此过程是非平稳的:相反,如果随机过程的特征不随时间而变化,就称此过程是平稳的.下图所示,左边非稳定,右边稳定. 非平稳时间序

时间序列模式(ARIMA)---Python实现

时间序列分析的主要目的是根据已有的历史数据对未来进行预测.如餐饮销售预测可以看做是基于时间序列的短期数据预测, 预测的对象时具体菜品的销售量. 1.时间序列算法: 常见的时间序列模型; ? 2.时序模型的预处理 1. 对于纯随机序列,也称为白噪声序列,序列的各项之间没有任何的关系, 序列在进行完全无序的随机波动, 可以终止对该序列的分析. 2. 对于平稳非白噪声序列, 它的均值和方差是常数.ARMA 模型是最常用的平稳序列拟合模型. 3. 对于非平稳序列, 由于它的方差和均值不稳定, 处理方法一

时间序列分析工具箱——sweep

目录 时间序列分析工具箱--sweep sweep 的用途 加载包 数据 Demo:forecast + sweep 的简化预测工作流 STEP 1:创建 ts 对象 STEP 2A:ARIMA 模型 STEP 2B:简化模型 STEP 3:预测 STEP 4:用 sweep 简化预测 STEP 5:比较真实值和预测值 翻译自<Demo Week: Tidy Forecasting with sweep> 原文链接:www.business-science.io/code-tools/2017

时间序列分析--指数平滑法

参考文献: http://blog.csdn.net/u013527419/article/details/52822622?locationNum=7&fps=1 一. 基础知识: 1. 概念:时间序列是指一个数据序列,特别是由一段时间内采集的信号组成的序列,序列前面的信号表示采集的时间较早. 2. 前提假设:时间序列分析一般假设我们获得的数据在时域上具有一定的相互依赖关系,例如股票价格在t时刻很高,那么在t+1时刻价格也会比较高(跌停才10%):如果股票价格在一段时间内获得稳定的上升,那么在