簡體   English   中英

為什么在切換循環時得到NaN?

[英]Why I am getting NaN when I toggle the loop?

我正在嘗試在javascript中編寫k-means函數。 這是我的代碼。

function kmeans(arrayToProcess,cluster_n){
    var pointDimension = arrayToProcess[0].length;
    var ClusterResult = new Array();
    var ClusterCenter = new Array();
    var oldClusterCenter = new Array();
    var changed=false;
    for(var i = 0;i<cluster_n;i++)
        ClusterCenter.push(arrayToProcess[randomInt(arrayToProcess.length-1)]);

    console.log(ClusterCenter);

    // do{
    for(var k=0;k<50;k++){//loop
        for(var i = 0; i<cluster_n; i++){
            ClusterResult[i] = new Array();
        }
        for(var i = 0; i<arrayToProcess.length; i++){
            //for every point element
            var oldDistance=-1;
            var newClusterNumber = 0;
            for(var j = 0; j<cluster_n; j++){
                //for every cluster
                var distance = Math.abs(computeDistanceBetween(arrayToProcess[i], ClusterCenter[j]));   
                if (oldDistance == -1){
                    oldDistance = distance;
                    newClusterNumber = j;
                }else if ( distance <= oldDistance ){
                    newClusterNumber = j;
                    oldDistance = distance;
                }
            }
            ClusterResult[newClusterNumber].push(arrayToProcess[i]);
        }
        oldClusterCenter = ClusterCenter;
        //compute new centroid
        for(var i = 0; i<cluster_n; i++){
            newCentroid = pinit(pointDimension);
            for(var j = 0; j<ClusterResult[i].length; j++){
                newCentroid = padd(ClusterResult[i][j], newCentroid);
            }
            ClusterCenter[i] = pdivide(newCentroid, ClusterResult[i].length);
        }

        changed=false;
        for(var i = 0; i<cluster_n; i++){
            if(!pequal(ClusterCenter[i],oldClusterCenter[i]))
                changed = true;
        }
    }//while (changed == true);

    return ClusterResult;
}


function computeDistanceBetween(a,b){
    var result = 0;
    for(var i = 0; i<a.length;i++) result += a[i] * b[i];
    return result;
}

function pinit(n){
    var result = new Array(n);
    for(var i=0;i<n;i++) result[i] = 0;
    return result;
}

function padd(a,b){
    var result = new Array(a.length);
    for(var i = 0; i<a.length;i++) result[i] = a[i] + b[i];
    return result;
}

function pdivide(a,d){
    var result = new Array(a.length);
    for(var i = 0; i<a.length;i++) result[i] = a[i] / d;
    return result;
}

function pequal(a,b){
    for(var i = 0; i<a.length;i++) 
        if(a[i] != b[i]) return false;
    return true;
}

function randomInt(max){
    return randomIntBetween(0,max);
}

function randomIntBetween(min,max){
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

如果我停止for-loop(k <0),則控制台會給出正確的答案。 但是,如果我啟動for-loop(k <1),則數組ClusterCenter將始終具有一些NaN項。 NaN的劑量如何?

編輯:進一步的解釋:如果已經執行了第14行中的for循環,則上面的ClusterCenter將給出一些NaN項。為什么?

輸入示例

var testArray = new Array();
for(var i=0; i<100; i++) testArray.push([randomInt(-150,150),randomInt(-150,150)]);
kmeans(testArray,4);

上面的ClusterCenter將給出一些NaN項。為什么?

因為您要零零潛水,所以這不是一個數字。 對於ClusterResult中的每個空群集,都確實會發生這種情況-它會創建ClusterCenter[i] = pdivide(pinit(pointDimension), 0);

如何處理空集群? 我想到的可能策略是使0/0 = 0 ,選擇一個新的隨機聚類中心或將聚類全部放在一起( cluster_n-- )。

但是,為什么首先要得到這么多的空簇呢? 因為您的computeDistanceBetween函數存在嚴重缺陷。 每個(非0 | 0)點都遠離自身 選擇一個更合理的距離函數,如歐氏距離。 它應始終返回一個正數,從而使Math.abs處於循環狀態。


其他一些要點:

  • newCentroid錯過了var語句並泄漏到全局范圍內
  • 您的changed有缺陷。 設置oldClusterCenter = ClusterCenter ,兩個變量都將保存相同的數組 ,然后對其進行突變。 不僅pequal(ClusterCenter[i],oldClusterCenter[i])始終為true,而且因為oldClusterCenter === ClusterCenter ,甚至ClusterCenter[i]===oldClusterCenter[i]

    要解決此問題,可以使oldClusterCenter = ClusterCenter.slice()或引入ClusterCenter = new Array(cluster_n); 分配后。

  • 您用於計算最近群集的代碼可以簡化為

     var newClusterNumber = 0, oldDistance = computeDistanceBetween(arrayToProcess[i], ClusterCenter[0])); for (var j=1; j<cluster_n; j++) { var distance = computeDistanceBetween(arrayToProcess[i], ClusterCenter[j]); if (distance <= oldDistance) { newClusterNumber = j; oldDistance = distance; } } 

    要么

     var onewClusterNumber, ldDistance=Infinity; for (var j=0; j<cluster_n; j++) { var distance = computeDistanceBetween(arrayToProcess[i], ClusterCenter[j]); if (distance <= oldDistance) { newClusterNumber = j; oldDistance = distance; } } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM