1. 程式人生 > >利用格拉布斯準則,剔除異常資料

利用格拉布斯準則,剔除異常資料

一:步驟解說:

1、排列資料 Collections.sort(dataArrayList);

2、求平均值、標準差

3、計算Gi值:每個資料與平均數的殘差 / 標準差

4、用這個Gi 值 與  格拉布斯臨界表表中的 臨界值比較,越大,越異常,需剔除

注:

  1. 這個臨界值 與 頂尖水平(alpha)有關 在0.01 - 0.99中選,越小越嚴格 ,以及測量次數(陣列集合長度)
  2. 查格拉布斯表獲得臨界值: 根據 置信概率(1-alpha) 和測驗次數 橫縱交得臨界值

程式碼

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Truncat {    
    private ArrayList<Double> dataArrayList;
    private int length;
    private final double alpha = 0.05;
    //傳入一組資料,我們要做的是剔除最大或最小的異常值
    public Truncat(ArrayList<Double> arrayList) {
        this.dataArrayList = arrayList;
        this.length = arrayList.size();
    }

    public ArrayList<Double> calc() {
    //因為格拉布斯準則只能對大於等於3個數據進行判斷,所以資料量小於3時,直接返回
        if (dataArrayList.size() < 3) {
            return dataArrayList;
        }
        //首先對資料進行排序
        Collections.sort(dataArrayList);
        //求出資料平均值和標準差
        double average = calcAverage(dataArrayList);
        double standard = calcStandard(dataArrayList, length, average);
        // 迴圈取每個資料和平均資料的標準差,過了就剔除!
        Iterator<Double> it = dataArrayList.iterator();
        while(it.hasNext()){
            Double item = it.next();
            //與平均值之差
            double diffAvg  = (item>average)?(item-average):(average-item);
            //差值/標準差
            double waveValue = diffAvg/standard;//波動
            //做比較,是否剔除
            if (waveValue > calcG(alpha, length)) {
                it.remove();
            }
        }
        return dataArrayList;
    }
    
    //求平均
    public double calcAverage(ArrayList<Double> sample) {
        double sum = 0;
        int cnt = 0;
        for (int i = 0; i < sample.size(); i++) {
            sum += sample.get(i);
            cnt++;
        }

        return (double) sum / cnt;
    }
    
    //求標準差
    private double calcStandard(ArrayList<Double> array, int n, double average) {
        double sum = 0;
        for (int i = 0; i < n; i++) {
            sum += ((double) array.get(i) - average)
                    * ((double) array.get(i) - average);
        }
        return (double) Math.sqrt((sum / (n - 1)));
    }
    
    //算臨界值的表,這裡alpha為0.05
    private double calcG(double alpha, int n) {
        double[] N = { 1.1546847100299753, 1.4962499999999703,
                1.763678479497787, 1.9728167175443088, 2.1391059896012203,
                2.2743651271139984, 2.386809875078279, 2.4820832497170997,
                2.564121252001767, 2.6357330437346365, 2.698971864039854,
                2.755372404941574, 2.8061052912205966, 2.8520798130619083,
                2.894013795424427, 2.932482154393285, 2.9679513293748547,
                3.0008041587489247, 3.031358153993366, 3.0598791335206963,
                3.086591582831163, 3.1116865231590722, 3.135327688211162,
                3.157656337622164, 3.178795077984819, 3.198850919445483,
                3.2179177419513314, 3.2360783011390764, 3.2534058719727748,
                3.26996560491852, 3.2858156522011304, 3.301008108808857,
                3.31558980320037, 3.329602965279218, 3.3430857935316243,
                3.356072938839107, 3.368595919061223, 3.3806834758032323,
                3.3923618826659503, 3.403655212591846, 3.41458557057518,
                3.4251732969213213, 3.435437145364717, 3.4453944396432576,
                3.4550612115453876, 3.464452322969104, 3.4735815741386,
                3.482461799798589, 3.491104954935569, 3.4995221913492585,
                3.507723926208097, 3.5157199035634887, 3.5235192496631433,
                3.5311305227901078, 3.5385617582575746, 3.5458205091071684,
                3.5529138829882037, 3.5598485756350797 };

        return N[n - 3];
    }
}