有时候我们需要在Java里对时间序列的数据进行简单地预测,通过其他语言(Python或R)来实现会极大的提高开发和运维成本.另外,很多数学模型的原理比较复杂,并且涉及到模型训练和参数调优,这些也会加大我们的时间投入.本文尝试向大家分享一个不需要了解算法、不需要参数调优就可以直接引用的实现方式.
添加依赖
当前Java可应用的第三方库非常少,通过对比后选择了下面的依赖,大家可以参考Github的文档和源码.
<dependency>
<groupId>com.github.jrachiele</groupId>
<artifactId>java-timeseries</artifactId>
<version>0.2.1</version>
</dependency>
代码
如果你只想要一个可以引用的代码,你只需要在你的代码中调用下面的方法:
TimeSeriesPredictUtil.predict(data, 7, false);
其中, data是你的历史时间序列, 7是需要未来多少个数据, false代表不绘图.
为了你上面的引用有效,你还需要将下面的TimeSeriesPredictUtil类复制到你的项目中:
package org.test;
import timeseries.TimeSeries;
import timeseries.models.Forecast;
import timeseries.models.arima.Arima;
import java.util.ArrayList;
public class TimeSeriesPredictUtil {
private TimeSeriesPredictUtil() {
}
/**
* 调用第三方库并对时间序列进行预测,输入对数据需要是有序甚至规律的时间序列。另外,不需要输入时间时间,
* 如果你需要得到时间和预测值的键值对,你需要自己组装
*
* @param data 需要预测的数据
* @param steps 你需要预测未来多少个单位的数据,比如5天,5周或者5个月。
* @param draw 是否绘图,测试时可以通过绘图直观的翻译数据预测是否准确
* @return 预测值数组
*/
public static double[] predict(double[] data, int steps, boolean draw) {
TimeSeries series = new TimeSeries(data);
ArrayList<Integer> options = new ArrayList<>();
int[] params = new int[]{0, 1, 2};
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
repeatableArrangement(3, params, options, result);
ArrayList<Integer> bestChoice = new ArrayList<>(3);
ArrayList<Integer> sBestChoice = new ArrayList<>(6);
double minimalAic = Double.MAX_VALUE;
for (ArrayList<Integer> item : result) {
if (item.isEmpty()) {
continue;
}
Arima.ModelOrder order = Arima.order(item.get(0), item.get(1), item.get(2));
Arima model = Arima.model(series, order);
double aic = model.aic();
if (aic < minimalAic) {
minimalAic = aic;
bestChoice.clear();
bestChoice.addAll(item);
sBestChoice.clear();
}
for (ArrayList<Integer> sItem : result) {
if (sItem.isEmpty()) {
continue;
}
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);
double sAic = sModel.aic();
if (sAic < minimalAic) {
minimalAic = sAic;
bestChoice.clear();
sBestChoice.clear();
sBestChoice.addAll(item);
sBestChoice.addAll(sItem);
}
}
}
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);
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);
}
}
}
}
结论
本文给出了使用ARIMA预测时间序列的实现方式,其中包括了参数自动生成,也支持季节性性数据的预测.如果你需要更深入的了解时间序列预测,你可以深入学习ARIMA算法原理,包括参数确定等.最后,你还可以去了解LSTM预测时间序列.