Javascript 为什么我在切换循环时得到NaN?

Javascript 为什么我在切换循环时得到NaN?,javascript,Javascript,我正在尝试用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(); v

我正在尝试用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;
}
函数kmeans(arrayToProcess,群集){
var pointDimension=arrayToProcess[0]。长度;
var ClusterResult=新数组();
var ClusterCenter=新数组();
var oldClusterCenter=新数组();
var=false;
对于(var i=0;i
上面的ClusterCenter将提供一些NaN项目。为什么

因为您正在以零对零跳转,这不是一个数字。这确实会发生在
ClusterResult
中的每个空集群上-它将创建
ClusterCenter[i]=pdivide(pinit(pointDimension),0);

如何处理空集群?我可能想到的策略是使
0/0=0
,选择一个新的随机集群中心,或者将集群全部丢弃(
cluster\n--

但是为什么一开始就有这么多空的集群呢?因为你的
computeDistanceBetween
函数有严重缺陷。每一个(非0 | 0)点与自身相距较远。请选择更合理的距离函数,如欧几里德距离。它应始终返回正数,以呈现循环中的
数学.abs


其他几点:

  • newCentroid
    遗漏
    var
    语句并泄漏到全局范围
  • 您的
    更改的
    存在缺陷。设置
    oldClusterCenter=ClusterCenter
    时,两个变量将保留相同的数组,然后进行变异。不仅
    pequal(ClusterCenter[i],oldClusterCenter[i])
    始终为真,甚至
    ClusterCenter[i]==oldClusterCenter[i]
    因为
    oldClusterCenter===ClusterCenter

    要解决此问题,请在分配后生成
    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 newClusterNumber=0,
    oldDistance=ComputedDistanceBetween(arrayToProcess[i],ClusterCenter[0]);
    
    对于(var j=1;jfyn=不是一个数),当你在数学运算的中间放一些“不数字”时,JS返回这个例子。你能提供一些示例输入吗?还有,“如果我停止循环”和“如果我启动循环”意味着什么,代码的变化仅仅是不起作用的吗?@贝尔吉谢谢你的回答。我增加了“进一步的解释”。“示例输入”。@enapupe:实际上,这里的值确实来自对数字的数学运算:-)除以零返回“无穷大”@enapupe:请试试!什么是
    0/0
    Infinity/Infinity
    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;
        }
    }