ARIMA时间序列(JAVA示例代码,含注释)

发布时间:2023年12月20日

参考地址:https://github.com/signaflo/java-timeseries/wiki/ARIMA%20models

以天为维度进行预测,考虑季节性P D Q,基于java-timeseries-0.2.1实现。算法模型上p、d、q阶差在3以内,阶差超过超过3,数据失真的可能性较高,所以我们设定3以内的阶差;拟合策略为USS,同时考虑季节性P D Q阶差,具体的p、d、q比例,选取所有的组合,通过AIC原则确定最优拟合方案,3以内的超参进行运算次数为(3*3*3)*(3*3*3)次,如果扩大超参运行增大,拟合策略为 CSSML(条件平方和,然后是最大似然), 除此之外还有:CSS, ML, CSSML, USS, USSML。

pom.xml中引入

		<dependency>
		    <groupId>com.github.jrachiele</groupId>
		    <artifactId>java-timeseries</artifactId>
		    <version>0.2.1</version>
		</dependency>

创建工具类ArimaUti.java


import java.util.ArrayList;

import timeseries.TimeSeries;
import timeseries.Ts;
import timeseries.models.Forecast;
import timeseries.models.arima.Arima;
import timeseries.models.arima.Arima.FittingStrategy;

public class ArimaUtil {

	/**
	 * github地址:https://github.com/signaflo/java-timeseries/wiki/ARIMA%20models
	 * 
	 * @param args
	 */

	public static void main(String[] args) {
		// 1、数据预处理,专家和程序相结合,以专家经验为主;
		// 2、算法模型上p、d、q阶差在3以内,阶差超过超过3,数据失真的可能性较高,所以我们设定3以内的阶差;拟合策略为USS,同时考虑季节性P D
		// Q阶差,具体的p、d、q比例,选取所有的组合,通过AIC原则确定最优拟合方案。
		

		double[] data1 = new double[] { 125313.00, 137269.00, 244490.00, 287543.00, 324499.00, 311067.00, 259425.00,
				329819.00, 434853.00, 429448.00, 632888.00, 772799.00, 300053.00, 396290.00, 297682.00, 427363.00,
				322505.00, 319447.00, 322702.00, 325893.00, 329232.00, 309768.00, 474377.00, 528164.00, 240786.00,
				164162.00, 312354.00, 293259.00, 318812.00, 300855.00, 280806.00, 329902.00, 449946.00, 475666.00,
				503628.00, 751930.00, 390240.00, 258080.00, 433766.00, 373354.00, 392186.00, 398683.00, 511023.00,
				509940.00, 551645.00, 627801.00, 577502.00, 722013.00, 287564.00, 393840.00, 460964.00, 394089.00,
				387435.00, 401763.00, 455938.00, 433146.00, 466803.00, 541699.00, 536455.00, 611227.00, 288705.00,
				212319.00, 358225.00, 269655.00, 323315.00, 245326.00, 293882.00, 319587.00, 382168.00, 392402.00,
				529535.00, 684079.00, 299872.00, 370931.00, 376959.00, 353275.00, 295286.00, 536354.00, 289498.00,
				258752.00, 376137.00, 398256.00, 284366.00, 548489.00, 557731.00, 139582.00, 434978.00, 329646.00,
				329098.00, 476521.00, 397364.00, 394842.00, 506988.00, 605346.00, 682207.00, 834749.00, 663517.00,
				703500.00, 861919.00, 875020.00, 611936.00, 932294.00, 893144.00, 883730.00, 900516.00, 900587.00,
				1075590.0, 1016250.0, 783064.00, 919727.00, 917302.00, 1016711.0, 776010.00, 876441.00, 988196.00,
				798981.00, 1108645.0, 1132921.0, 1255781.0, 1202435.0, 1016490.0, 935281.00, 1270376.0, 1336770.0,
				1437635.0, 1555010.0, 1705866.0, 1689584.0, 1861612.0, 1819093.0, 2537813.00, 2011416.00 };

		// 季节性ARIMA建模的开放源码时间序列库java-timeseries进行预测,开源MIT协议
		// 拟合策略为 CSSML(条件平方和,然后是最大似然), 除此之外还有:CSS, ML, CSSML, USSML;
		// 阶数在3以内,考虑季节性p、d、q阶数,通过AIC原则评估阶数拟合度。计算出最佳拟合阶数。
		double[] predictResult = TimeSeriesPredictUtil.predictByDay(data1, 7, false, 2022, 10, 1);
		System.out.println(predictResult.length);
		System.out.println("----预测结果:" + predictResult.toString());

		for (int i = 0; i < predictResult.length; i++) {
			System.out.print(predictResult[i]);

			System.out.print(",");
		}

	}

	private TimeSeriesPredictUtil() {
	}

	/**
	 * 调用第三方库并对时间序列进行预测,输入对数据需要是有序甚至规律的时间序列。另外,不需要输入时间时间, 如果你需要得到时间和预测值的键值对,你需要自己组装
	 *
	 * @param data       需要预测的数据
	 * @param steps      你需要预测未来多少个单位的数据,比如5天,5周或者5个月。
	 * @param draw       是否绘图,测试时可以通过绘图直观的翻译数据预测是否准确
	 * @param startYear  The year of the first observation.
	 * @param startMonth The month of the first observation - an integer between 1
	 *                   and 12 corresponding to the months January through
	 *                   December.
	 * @param startDay   The day of the first observation - an integer between 1 and
	 *                   31.
	 * @return 预测值数组
	 */
	public static double[] predictByDay(double[] data, int steps, boolean draw, int startYear, int startMonth,
			int startDay) {
		// 指定周期
		TimeSeries series = Ts.newMonthlySeries(startYear, startMonth, startDay, data);// 开始时间,年、 月( 1 and 12)、 日(1 and 31)、 历史数据

		ArrayList<Integer> options = new ArrayList<>();
		// 差分阶数,3次以内
		int[] params = new int[] { 0, 1, 2 };
		ArrayList<ArrayList<Integer>> result = new ArrayList<>();

		// 模型顺序 pdq
		repeatableArrangement(3, params, options, result);

		// 测试预测一次
//		result.add(new ArrayList<>(Arrays.asList(1, 1, 1)));
		
		
		// d 差分次数,数据平稳差分次数,差分太多失真
		// p 自回归参数,ar模型
		// q 滑动平均参数,MA模型
		// 其中(P, D, Q, s)表示季节性ARIMA模型的季节性阶数,
		ArrayList<Integer> bestChoice = new ArrayList<>(3); // 三个参数,p、d、q , 表示AR、差分、MA的阶数
		ArrayList<Integer> sBestChoice = new ArrayList<>(6);// 六个参数,p, d, q, P, D, Q
		double minimalAic = Double.MAX_VALUE;
		for (ArrayList<Integer> item : result) {
			if (item.isEmpty()) {
				continue;
			}
			// 第二步,我们可以指定任何我们认为合理的模型顺序
			// Note that intercept fitting will automatically be turned off 适当拟合将自动关闭
			Arima.ModelOrder order = Arima.order(item.get(0), item.get(1), item.get(2));
			// 创建arima模型
			// 默认拟合策略 uss ,除此之外还有:CSS, ML, CSSML, USSML;
			// USS("Uncorrected Sum of Squares"), 未校正平方和
			// CSS("conditional sum-of-squares"), 有条件的平方和
			// ML("maximum likelihood"), 最大似然
			// CSSML("conditional sum-of-squares, then maximum likelihood");
			Arima model = Arima.model(series, order, FittingStrategy.CSSML);
			double aic = model.aic();
			// 利用三个参数 pdq ,采用AIC原则 (最小化信息量准则)
			if (aic < minimalAic) {
				minimalAic = aic;
				bestChoice.clear();
				bestChoice.addAll(item);

				sBestChoice.clear();
			}
			// 利用三个参数 pdq ,采用AIC原则 (最小化信息量准则)
			for (ArrayList<Integer> sItem : result) {
				if (sItem.isEmpty()) {
					continue;
				}
				// 除了数据p 、d q ,考虑季节性P D Q
				Arima.ModelOrder sOrder = Arima.order(item.get(0), item.get(1), item.get(2), sItem.get(0), sItem.get(1),
						sItem.get(2));
				Arima sModel = Arima.model(series, sOrder, FittingStrategy.CSSML);
				// 计算AIC
				double sAic = sModel.aic();
				// 最小原则
				if (sAic < minimalAic) {
					minimalAic = sAic;
					bestChoice.clear();

					sBestChoice.clear();
					sBestChoice.addAll(item);
					sBestChoice.addAll(sItem);
				}
			}
		}
		// 确定 p d q,还是 p, d, q, P, D, Q 后预测
		// 如果考虑季节性方案最优使用季节性,如果不考虑季节最优就只使用三个参数
		Arima.ModelOrder order = sBestChoice.isEmpty()
				? Arima.order(bestChoice.get(0), bestChoice.get(1), bestChoice.get(2))
				: Arima.order(sBestChoice.get(0), sBestChoice.get(1), sBestChoice.get(2), sBestChoice.get(3),
						sBestChoice.get(4), sBestChoice.get(5));
		Arima model = Arima.model(series, order, FittingStrategy.CSSML);
		// 执行预测
		Forecast forecast = model.forecast(steps);

		if (draw) {
			// 绘图
			forecast.plot();
		}
		// 返回预测结果
		return forecast.forecast().asArray();
	}

	// 递归获得所有不重复的阶差组合
	private static void repeatableArrangement(int k, int[] arr, ArrayList<Integer> tmpArr,
			ArrayList<ArrayList<Integer>> result) {
		if (k == 1) {
			for (int j : arr) {
				tmpArr.add(j);
				ArrayList<Integer> tmp = new ArrayList<>(tmpArr);
				result.add(tmp);
				tmpArr.remove(tmpArr.size() - 1);
			}
		} else if (k > 1) {
			for (int j : arr) {
				tmpArr.add(j);
				repeatableArrangement(k - 1, arr, tmpArr, result);
				tmpArr.remove(tmpArr.size() - 1);
			}
		}
	}
}

文章来源:https://blog.csdn.net/myfmyfmyfmyf/article/details/135109959
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。