6

履歴データを使用して予測を実行できる Java で記述されたシステムに取り組んでいます。使用されているアルゴリズムは、この Holt-Winters 実装(乗法季節性) の Java ポートです。

分析したい時系列がいくつかあり、それらの時系列には異なる平滑化係数が必要です。アルゴリズムは現時点で非常にうまく機能しているようですが、唯一の問題は、平滑化係数 (アルファ、ベータ、ガンマ) の最も適切な値を決定する方法です。

ある種の非線形最適化が必要であることは知っていますが、私は数学者ではないので、これらすべての理論や概念の中で少し迷っています。

編集

分析するさまざまな時系列がたくさんあります。Holt-Winters アルゴリズムに与える必要がある平滑化パラメーターを計算するための標準/適切な手法 (ライブラリの方がよいでしょう) があるかどうかを知りたいです。

4

2 に答える 2

4

JMulTiを調べましたか?

この SO の質問は、あなたに非常に関連している可能性があります。

Holt-Winters について調べている人は、必ずHyndman 教授のサイトをチェックしてください。彼はドメインの専門家であり、forecast()R のライブラリの作成者でもあります。

このテクニックをもっと理解したいとおっしゃいましたね。良いニュースは、Hyndman が執筆中の教科書で、無料で閲覧できます。Holt-winters に関する特定の章は、http: //otexts.com/fpp/7/5/にあります。

Javaでそれを望んでいたことは知っていますが、Rがオプションである場合は、試してみてください。(R から書いて Java プログラムに読み込むことを推奨する人もいます。)

アップデート:

気になるのが最初の HW パラメーターである場合、パラメーターに到達するための最尤検索をets実装するパッケージしか思い浮かびません。Java 実装が見つからない場合、最善の策は、JRI (rJava)を使用して、その中からorを呼び出すことです。etsHoltWinters

それが役立つことを願っています。

于 2012-09-24T23:11:09.817 に答える
3

Apache によって実装されたNelder Mead Optimizer (SimplexOptimizer)を利用できます。

double[] dataPoints = {
            141, 53, 78, 137, 182, 161, 177,
            164, 70, 67, 129, 187, 161, 136,
            167, 57, 61, 159, 158, 152, 169,
            181, 65, 60, 146, 186, 180, 181,
            167, 70, 62, 170, 193, 167, 176,
            149, 69, 68, 168, 181, 200, 179,
            181, 83, 72, 157, 188, 193, 173,
            184, 61, 59, 158, 158, 143, 208,
            172, 82, 86, 158, 194, 193, 159
};

NelderMeadOptimizer.Parameters op = NelderMeadOptimizer.optimize(dataPoints, 7);
op.getAlpha(); 
op.getBeta(); 
op.getGamma();

次に、NelderMeadOptimizer が必要です。

import org.apache.commons.math3.analysis.MultivariateFunction;
import org.apache.commons.math3.optim.InitialGuess;
import org.apache.commons.math3.optim.MaxEval;
import org.apache.commons.math3.optim.MaxIter;
import org.apache.commons.math3.optim.PointValuePair;
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType;
import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateFunctionMappingAdapter;
import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction;
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex;
import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer;

import java.util.List;

public class NelderMeadOptimizer {

    // configuration
    private static final double minValueForOptimizedParameters = 0.001;
    private static final double maxValueForOptimizedParameters = 0.99;
    private static final double simplexRelativeThreshold = 0.0001;
    private static final double simplexAbsoluteThreshold = 0.0001;

    private static final double DEFAULT_LEVEL_SMOOTHING = 0.01;
    private static final double DEFAULT_TREND_SMOOTHING = 0.01;
    private static final double DEFAULT_SEASONAL_SMOOTHING = 0.01;

    private static final int MAX_ALLOWED_NUMBER_OF_ITERATION = 1000;
    private static final int MAX_ALLOWED_NUMBER_OF_EVALUATION = 1000;

    /**
     *
     * @param dataPoints the observed data points
     * @param seasonLength the amount of data points per season
     * @return the optimized parameters
     */
    public static Parameters optimize(double[] dataPoints, int seasonLength) {
        MultivariateFunctionMappingAdapter costFunc = getCostFunction(dataPoints, seasonLength);
        double[] initialGuess = getInitialGuess(dataPoints, seasonLength);
        double[] optimizedValues = optimize(initialGuess, costFunc);
        double alpha = optimizedValues[0];
        double beta = optimizedValues[1];
        double gamma = optimizedValues[2];
        return new Parameters(alpha, beta, gamma);
    }

    /**
     * Optimizes parameters using the Nelder-Mead Method
     * @param initialGuess initial guess / state required for Nelder-Mead-Method
     * @param costFunction which defines that the Mean Squared Error has to be minimized
     * @return the optimized values
     */
    private static double[] optimize(double[] initialGuess, MultivariateFunctionMappingAdapter costFunction) {
        double[] result;

        SimplexOptimizer optimizer = new SimplexOptimizer(simplexRelativeThreshold, simplexAbsoluteThreshold);

        PointValuePair unBoundedResult = optimizer.optimize(
                GoalType.MINIMIZE,
                new MaxIter(MAX_ALLOWED_NUMBER_OF_ITERATION),
                new MaxEval(MAX_ALLOWED_NUMBER_OF_EVALUATION),
                new InitialGuess(initialGuess),
                new ObjectiveFunction(costFunction),
                new NelderMeadSimplex(initialGuess.length));

        result = costFunction.unboundedToBounded(unBoundedResult.getPoint());
        return result;
    }


    /**
     * Defines that the Mean Squared Error has to be minimized
     * in order to get optimized / good parameters for alpha, betta and gamma.
     * It also defines the minimum and maximum values for the parameters to optimize.
     * @param dataPoints the data points
     * @param seasonLength the amount of data points per season
     * @return a cost function  {@link MultivariateFunctionMappingAdapter} which
     * defines that the Mean Squared Error has to be minimized
     * in order to get optimized / good parameters for alpha, betta and gamma
     */
    private static MultivariateFunctionMappingAdapter getCostFunction(final double[] dataPoints, final int seasonLength) {

        MultivariateFunction multivariateFunction = new MultivariateFunction() {
            @Override
            public double value(double[] point) {
                double alpha = point[0];
                double beta = point[1];
                double gamma = point[2];

                if (beta >= alpha) {
                    return Double.POSITIVE_INFINITY;
                }

                List<Double> predictedValues = TripleExponentialSmoothing.getSmoothedDataPointsWithPredictions(dataPoints, seasonLength, alpha, beta, gamma, 1);

                predictedValues.remove(predictedValues.size()-1);

                double meanSquaredError = getMeanSquaredError(dataPoints, predictedValues);
                return meanSquaredError;
            }
        };

        double[][] minMax = getMinMaxValues();
        return new MultivariateFunctionMappingAdapter(multivariateFunction, minMax[0], minMax[1]);
    }

    /**
     * Generates an initial guess/state required for Nelder-Mead-Method.
     * @param dataPoints the data points
     * @param seasonLength the amount of data points per season
     * @return array containing initial guess/state required for Nelder-Mead-Method
     */
    public static double[] getInitialGuess(double[] dataPoints, int seasonLength){
        double[] initialGuess = new double[3];
        initialGuess[0] = DEFAULT_LEVEL_SMOOTHING;
        initialGuess[1] = DEFAULT_TREND_SMOOTHING;
        initialGuess[2] = DEFAULT_SEASONAL_SMOOTHING;
        return initialGuess;
    }

    /**
     * Get minimum and maximum values for the parameters alpha (level coefficient),
     * beta (trend coefficient) and gamma (seasonality coefficient)
     * @return array containing all minimum and maximum values for the parameters alpha, beta and gamma
     */
    private static double[][] getMinMaxValues() {
        double[] min = new double[3];
        double[] max = new double[3];
        min[0] = minValueForOptimizedParameters;
        min[1] = minValueForOptimizedParameters;
        min[2] = minValueForOptimizedParameters;

        max[0] = maxValueForOptimizedParameters;
        max[1] = maxValueForOptimizedParameters;
        max[2] = maxValueForOptimizedParameters;
        return new double[][]{min, max};
    }


    /**
     * Compares observed data points from the past and predicted data points
     * in order to calculate the Mean Squared Error (MSE)
     * @param observedData the observed data points from the past
     * @param predictedData the predicted data points
     * @return the Mean Squared Error (MSE)
     */
    public static double getMeanSquaredError(double[] observedData, List<Double> predictedData){
        double sum = 0;

        for(int i=0; i<observedData.length; i++){
            double error = observedData[i] - predictedData.get(i);
            double sumSquaredError = error * error; // SSE
            sum += sumSquaredError;
        }

        return sum / observedData.length;
    }

    /**
     * Holds the parameters alpha (level coefficient), beta (trend coefficient)
     * and gamma (seasonality coefficient) for Triple Exponential Smoothing.
     */
    public static class Parameters {
        public final double alpha;
        public final double beta;
        public final double gamma;

        public Parameters(double alpha, double beta, double gamma) {
            this.alpha = alpha;
            this.beta = beta;
            this.gamma = gamma;
        }

        public double getAlpha() {
            return alpha;
        }

        public double getBeta() {
            return beta;
        }

        public double getGamma() {
            return gamma;
        }
    };
}
于 2018-02-15T10:57:03.547 に答える