javascript - Why I am getting NaN when I toggle the loop? -
i'm trying write k-means function in javascript. , here code.
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 = 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 = 0; i<cluster_n; i++){ clusterresult[i] = new array(); } for(var = 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 = 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 = 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 = 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 = 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 = 0; i<a.length;i++) result[i] = a[i] / d; return result; } function pequal(a,b){ for(var = 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; }
if stop for-loop(k<0), console gives right answer. if start for-loop(k<1),the array clustercenter has nan items. how dose nan appear?
edit: further explanation: if for-loop in 14th line has been executed, clustercenter above give nan items.why?
example input
var testarray = new array(); for(var i=0; i<100; i++) testarray.push([randomint(-150,150),randomint(-150,150)]); kmeans(testarray,4);
the clustercenter above give nan items.why?
because you're diving 0 zero, not number. happen every empty cluster in clusterresult
- create clustercenter[i] = pdivide(pinit(pointdimension), 0);
.
how deal empty clusters? possible strategies think of make 0/0 = 0
, choose new random cluster center, or drop cluster alltogether (cluster_n--
).
but why many empty clusters in first place? because computedistancebetween
function flawed. every (non-0|0) point distant itself. choose more reasonable distance function, euclidian distance. should return positive number, rendering math.abs
in loop superflouos.
some other points:
newcentroid
missesvar
statement , leaks global scopeyour
changed
flawed. when settingoldclustercenter = clustercenter
, both variables hold same array mutated. notpequal(clustercenter[i],oldclustercenter[i])
true,clustercenter[i]===oldclustercenter[i]
because ofoldclustercenter === clustercenter
.to fix this, either make
oldclustercenter = clustercenter.slice()
or introduceclustercenter = new array(cluster_n);
after assignment.your code computing nearest cluster simplified to
var newclusternumber = 0, olddistance = computedistancebetween(arraytoprocess[i], clustercenter[0])); (var j=1; j<cluster_n; j++) { var distance = computedistancebetween(arraytoprocess[i], clustercenter[j]); if (distance <= olddistance) { newclusternumber = j; olddistance = distance; } }
or
var onewclusternumber, lddistance=infinity; (var j=0; j<cluster_n; j++) { var distance = computedistancebetween(arraytoprocess[i], clustercenter[j]); if (distance <= olddistance) { newclusternumber = j; olddistance = distance; } }
Comments
Post a Comment