JS 對數據進行 正態分布擬合對比(echarts 做圖)


對一組看似正態分布的數據進行標准正態分布的擬合,用來做對比

准備:math.js

給定一組數據

yData = [
53, 53, 58.5, 78, 115, 154.5, 200, 300.5, 383.5, 518, 871.5, 1382.5, 2192.5, 3340.5, 5249, 8979.5, 15448, 26225, 44057.5, 71392, 109113, 159006, 224595.5, 307191.5, 405623, 520332, 646965.5, 785170.5, 930962.5, 1078572.5, 1227179.5, 1373870, 1522723.5, 1671622.5, 1812839.5, 1944963, 2068185, 2180604.5, 2280685.5, 2361196.5, 2417123.5, 2457786, 2483891, 2494890, 2496943.5, 2498862.5, 2500857.5, 2500175, 2501485, 2499141, 2492862, 2478390, 2459869.5, 2443707, 2430140, 2421345.5, 2404805, 2377592.5, 2334130, 2263164, 2163510.5, 2031018.5, 1872739.5, 1698482, 1507286, 1306381.5, 1114865.5, 938499, 771654.5, 619227.5, 488654.5, 379699.5, 289925.5, 218837.5, 165510.5, 126806, 97552, 75560, 59062, 46304.5, 36476, 28583, 22280.5, 16965.5, 12631.5, 9265.5, 6629, 4548.5, 3091, 2102.5, 1396.5, 921, 580, 345, 203.5, 137, 87, 46, 27.5, 12, 6
]

xData=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

繪制的圖形如下

 

 

 現在要對這個曲線進行正態分布的擬合

  1.求出均值

    

var yArr = [];var sumFuc = (s, c) => formulaCalcByFunc(s + c, 6);//求和匿名函數,formulaCalc為了減少精度誤差,可以自己寫var ysum = yData.reduce(sumFuc, 0);
for (var n = 0; n < yData.length; n++) {
var y = yData[n] / ysum;
yArr.push(y);
}
var avg = math.mean(yArr);

 

  2.編寫最小二乘法高斯擬合函數

function gaussFit(xOriginal, yOriginal, average) {
    var x = [];
    var y = [];
    // 過濾平滑部分
    for (var i = 0; i < yOriginal.length; i++)
        if (yOriginal[i] > average) {
            x.push(xOriginal[i]);
            y.push(yOriginal[i]);
        }

    var zMatrix = math.matrix(math.log(y));
    var zMatrixT = math.transpose(zMatrix);
    var xMatrix = math.ones([y.length, 3]);

    for (var j = 0; j < y.length; j++) {
        xMatrix[j][1] = x[j];
        xMatrix[j][2] = x[j] * x[j];
    }
    // 最小二乘法
    var xMatrixT = math.transpose(xMatrix);
    var bMatrix = math.multiply(math.multiply(math.inv(math.multiply(xMatrixT,xMatrix)), xMatrixT), zMatrixT);

    var b2 = math.subset(bMatrix, math.index(2));
    var b1 = math.subset(bMatrix, math.index(1));
    var b0 = math.subset(bMatrix, math.index(0));

    var s = -1 / b2;
    var xMaxi = s * b1 / 2;//均值
    var yMaxi = math.exp(b0 + xMaxi * xMaxi / s);//正態分布歸一系數

    var yFit = []
    for (var n = 0; n < yOriginal.length; n++) {
        yFit.push(gaussFunc(xOriginal[n], xMaxi, yMaxi, s));
    }

    return yFit;
}
 
         
//正態分布公式
function gaussFunc(x, xMaxi, yMaxi, s) {
return yMaxi * math.exp(-((x - xMaxi) * (x - xMaxi) / s)); }

  3.求出y軸數據的系數,並還原出原始數據

datas2 = gaussFit(xArr, yArr, avg);
for (var k = 0; k < datas2.length; k++) {
    var l = datas2[k] / yArr[k];
    var y = yData[k] * l;
    yData2.push(y);
}

 

 

最終繪制的圖形如下:

 第二種方法,使用標准正態分布公式實現(結果將會偏向原始數據峰值):

/**
* 正態分布函數
* @@param x 數據
* @@param mean 平均數
* @@param stdev 標准差
*/
function normalDistributionfun(x, mean, stdev) {
    return (1 / (Math.sqrt(2 * Math.PI) * stdev)) * Math.exp(-1 * ((x - mean) * (x - mean)) / (2 * stdev * stdev));
}


function calcNormallineDta(xData, yData) {
            var result = [];
         
            var totalCount = 0;

            var firstMode = 0;//峰值起始位置
            var modeCount = 0;//找到目前數據的峰值
        
            for (var i = 0; i < yData.length;i++) {
                totalCount += yData[i];
                if (yData[i] > modeCount) {
                    modeCount = yData[i];
                    firstMode = i;
                }
             
            }
            //找出出x軸左右范圍內的均值(關鍵代碼)
            var mode = 0;
            var modeDuplicates = 0;
        
            var fellOffTop = true;

            for (var j = firstMode; j < yData.length; j ++) {
                if (yData[j] > yData[firstMode] - (yData[firstMode]/10)) {//10:分布線系數
                    mode += j ;
                    modeDuplicates++;
                }
                else {
                    fellOffTop = false;
                    break;
                }
            }

            var fellOffBottom = true;
        
            for (var k=firstMode-1;k>=0;k--) {
                if (yData[k] > yData[firstMode] - (yData[firstMode] / 10)) {//10:分布線系數
                    mode += k;
                    modeDuplicates++;
                }
                else {
                    fellOffBottom = false;
                    break;
                }
            }
            var mean;
            if (fellOffBottom || fellOffTop) {
               
                mean = firstMode;
            }
            else {
                mean = mode/ modeDuplicates;
            }
            //求出標准差
          
            var stdev = 0;
        
            for (var n = 0; n < yData.length;n++) {
                stdev += Math.pow((n - mean), 2) * yData[n];
            }
        
            stdev /= totalCount-1;
        
            stdev = Math.sqrt(stdev);
            //帶入正態分布公式
            for (var m = 0; m < yData.length;m++) {
                var probability =normalDistributionfun(m,mean,stdev);
                result.push(Math.round(probability * totalCount*100)/100);
            }
            return result;
        }
      

 

 

 

 

 完整代碼在echart作品上查看

作品地址:https://www.makeapie.com/editor.html?c=xBtzYvoXr2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM