移動平均に基づく時系列フィルタリング方法(Javaで実装)

 1移動平均の理解

  移動平均法は、最近の実際のデータ値のセットを使用して、ある期間または将来のいくつかの期間における会社の製品の需要と会社の生産能力を予測する一般的な方法です。移動平均法は、スポット予測に適しています。製品需要が急激に増加も減少もせず、季節要因がない場合、移動平均法は予測のランダムな変動を効果的に排除することができ、非常に便利です。移動平均法は、予測に使用される各要素の重みによって異なります

  移動平均法は、単純な平滑化予測手法であり、その基本的な考え方は、時系列データに基づいて、項目ごとに、長期的な傾向を反映するために、特定の数の項目を含む連続時間平均を順次計算することです。したがって、周期的な変化やランダムな変動により時系列の値が大きく変動し、イベントの発生傾向を示すことが難しい場合、移動平均法はこれらの要因の影響を排除し、発生の方向と傾向を示すことができます。イベント(つまり、トレンドライン)の分析を行い、トレンドラインに従って予測シーケンスの長期トレンドを分析します。

  移動平均法の種類

  移動平均法は、単純移動平均と加重移動平均に分けることができます。

 (1)単純移動平均法

  単純移動平均の各要素の重みは等しくなります。単純移動平均の計算式は次のとおりです。Ft=(At-1 + At-2 + At-3 +…+ At-n)/ nここで、

  ・ft-次の期間の予測値。

  ・n-移動平均の期間数。

  ・at-1-暫定的な実際の値。

  ・At-2、At-3、およびAt-nは、それぞれ最初の2つの期間、最初の3つの期間、および最初のnの期間の実際の値を表します。 
  

 (2)加重移動平均法

  加重移動平均は、固定スパン期間内の各変数値に異なる加重を与えます。原則は次のとおりです。各期間の過去の製品需要のデータ情報は、将来の期間の需要の予測に異なる影響を及ぼします。nを周期とする周期的な変化を除けば、対象周期から遠く離れた変数値の影響は比較的小さいため、重みを小さくする必要があります。加重移動平均法の計算式は次のとおりです。

  Ft = w1At-1 + w2At-2 + w3At-3 +…+ wnAt-nここで、

  ・w1-期間t-1の実際の売上の重み。

  ・w2-期間t-2の実際の売上の重み。

  ・wn-tn期間の実際の販売に対する権利

  ・n-予測期間の数; w1 + w2 +…+ wn = 1

  加重平均法を使用する場合、重みの選択は注意が必要な問題です。経験的方法と試行アルゴリズムは、重みを選択する最も簡単な方法です。一般的に言えば、最新のデータは将来の状況を最もよく予測できるため、重みを大きくする必要があります。たとえば、前月の利益と生産能力に基づいて、前月に基づくよりも翌月の利益と生産能力を見積もる方がよいでしょう。ただし、データが季節的である場合、重みも季節的である必要があります。

  移動平均法の長所と短所

  移動平均法を使用して予測することで、需要の急激な変動が予測結果に与える影響を滑らかにすることができます。ただし、移動平均法を使用する場合は、次の問題もあります。

  1.移動平均法の期間数を増やす(つまり、nの値を増やす)と、平滑化効果は向上しますが、予測値はデータの実際の変化に対する感度が低くなります。

  2.移動平均は必ずしもトレンドをうまく反映しているわけではありません。これは平均値であるため、予測値は常に過去のレベルにとどまり、将来的に変動が大きくなったり小さくなったりすることは期待できません。

  3.移動平均法では、過去のデータレコードが大量に必要になります。

   
   
  移動平均法の事例分析単純移動平均法の
不動産への適用2001年のある種の不動産 の価格を下表の2列目に示します。月額料金は不確実な要因の影響を受けるため、高額な場合と低額の場合があり、価格は大きく変動します。分析しないと開発動向を示すのは簡単ではありません。数ヶ月ごとの価格を合計して移動平均を計算し、移動平均時系列を確立すると、スムーズな開発トレンドから開発の変化の方向と程度を明確に確認でき、将来の価格を予測できます。

  移動平均を計算するときは、毎回数か月を使用して計算する必要があります。これは、時系列の序数と変化の期間に応じて決定する必要があります。序数が多く、変更期間が長い場合は、6か月ごと、さらには12か月ごとに計算できますが、逆に2か月ごとまたは5か月ごとに計算することもできます。2001年のこの例の不動産価格では、5か月ごとの実際の値を使用して移動平均が計算されます。計算方法は、1月から5月までの価格を合計して5で割ると684元/平方メートルになり、2月から6月までの価格を合計して5で割ると694元/平方メートルになります。 3月から7月まで5で割ると704元/平方メートルになります。以下同様です。表の3列目を参照してください。次に、5か月ごとの移動平均に基づいて月ごとの増加を計算します。表の4番目の列を参照してください。 
  

ここに写真の説明を書いてください

2002年1月のこのタイプの不動産の価格を予測する必要がある場合、計算方法は次のとおりです。最後の移動平均762は2002年1月から3か月離れているため、2002年1月のこのタイプの不動産の価格は次のようになります。予測値:762 + 12×3 = 798(元/平方メートル)

2移動平均のJava実装

  • 残りのポイントの数=ウィンドウの長さ-1 =必要な補数の数
  • 残りのポイントが考慮されない場合、結果の配列の最終的な戻りの長さ=元の配列の長さ-ウィンドウの長さ+ 1
import java.util.Arrays;

import static org.apache.commons.math.stat.StatUtils.mean;

/**
 * 滑动平均计算
 * Created by dandan.
 * 属性解释:
 * movWindowSize:移动平均计算的滑动窗口
 * movLeaveTemp:临时数组记录最后得不到均值处理的点
 * movResBuff:输出最终结果数组
 * movResBuffLen:输出最终结果数组长度
 * inputBuff:输入数据数组
 * winArray:滑动窗口所形成的数组
 * winArrayLen:滑动窗口所形成的数组长度
 * tempCal:原始数组+插值后的扩容数组
 */

public class movingAverage {

    private static final int WINDOWS = 5;
    private int movWindowSize = WINDOWS; //窗口大小

    public movingAverage() {

    }

    public movingAverage(int size) {

        movWindowSize = size;
    }

    // 均值滤波方法,输入一个inputBuff数组,返回一个movResBuff数组,两者下标不一样,所以定义不同的下标,inputBuff的下标为i,movResBuff的下标为movResBuffLen.
    // 同理,临时的winArray数组下表为winArrayLen
    public double[] movingAverageCal(double[] inputBuff) {
        int movResBuffLen = 0;
        int winArrayLen = 0;
        //定义返回结果数组
        double[] movResBuff = new double[inputBuff.length];
        //定义窗口数组
        double[] winArray = new double[movWindowSize];
        //求整体输入序列的平均值作为一个插值点
        double replace = mean(inputBuff);
        //对原始数组扩容,将插值点放进去.剩余点个数是窗口大小-1.需要补充值的个数等于剩余点的个数
        double[] tempCal = new double[inputBuff.length + movWindowSize-1];
        //拷贝原始数组到临时计算数组
        System.arraycopy(inputBuff, 0, tempCal, 0, inputBuff.length);
        //将平均值插入进去
        for (int m = inputBuff.length; m <tempCal.length ; m++) {
            tempCal[m]=replace;
        }
        //开始计算
        for (int i = 0; i < tempCal.length; i++) {
            if ((i + movWindowSize) > tempCal.length) {
                break; 
            } else { 
                for (int j = i; j < (movWindowSize + i); j++) {
                    winArray[winArrayLen] = tempCal[j];
                    winArrayLen++; 
                }
                movResBuff[movResBuffLen] = mean(winArray);
                movResBuffLen++;
                winArrayLen = 0; 
            } 
        }
        return movResBuff; 
    }

    public static void main(String[] args) {

       double[] inputBuff={670,680,690,680,700,720,730,740,740,760,780,790};

        movingAverage movingAverage = new movingAverage();

        double[] filter = movingAverage.movingAverageCal(inputBuff);

        System.out.println(filter.length);
        System.out.println(Arrays.toString(filter));
        System.out.println(mean(filter));

    }
}

3UDF機能の実現。

上記の戻り値に基づいて、固有値が再度平均化されます

import org.apache.hadoop.hive.ql.exec.UDF;
import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.math.stat.StatUtils.mean;

public class movingAverageFeaCal extends UDF {

    public static void main(String[] args) {
        String num_all = "3.1002," +
                "3.0984," +
                "3.147," +
                "3.197," +
                "3.1002," +
                "3.1002," +
                "3.0854," +
                "3.0982," +
                "3.12," +
                "3.09," +
                "3.a091";

        movingAverageFeaCal movingAverageFeaCal = new movingAverageFeaCal();

        Double evaluate = movingAverageFeaCal.evaluate(num_all, 3);
        System.out.println(evaluate);
    }


    public Double evaluate(String num_all,int windowSize) {

        if (num_all == null || num_all.isEmpty()) {
            return null;//参数不全,不需要计算
        }
        String[] numArr = num_all.split(",");
        List<Double> list = new ArrayList();
        double num = 0;

        if (numArr.length > 0) {
            for (String aNumArr : numArr) {
//                boolean flag = Utils.isNumber(numArr[i]);
                if (aNumArr != null && !aNumArr.isEmpty() && !aNumArr.equals("null") && !aNumArr.equals("NULL") && Utils.isNumber(aNumArr)) {
                    num = Double.parseDouble(aNumArr);
                    list.add(num);
                }
            }
            // Double[] arr1 = list.toArray(new Double[list.size()]);
            double[] inputBuff= list.stream().mapToDouble(i -> i).toArray();
            movingAverage movingAverage = new movingAverage(windowSize);
            double[] feaArr = movingAverage.movingAverageCal(inputBuff);
            return mean(feaArr);

        } else {
            return null;
        }

    }


}

 

おすすめ

転載: blog.csdn.net/godlovedaniel/article/details/114635797