bool MLP::calcGradient(const dmatrix& inputs, const ivector& ids, dvector& grad) { if (inputs.rows() != ids.size()) { setStatusString("Number of vectors not consistent with number of ids"); return false; } dvector tmp; int i; double tmpError; totalError = 0; calcGradient(inputs.getRow(0),ids.at(0),grad); computeActualError(ids.at(0),totalError); for (i=1;i<inputs.rows();++i) { calcGradient(inputs.getRow(i),ids.at(i),tmp); computeActualError(ids.at(i),tmpError); grad.add(tmp); totalError+=tmpError; } return true; }
bool modHubertStat::apply(const std::vector<dmatrix>& clusteredData, double& index, const dmatrix& centroids) const { index =0.0; int nbClusters=clusteredData.size(); l2Distance<double> dist; int nbPoints=0; int i,j,k,l; for (i=0; i<nbClusters; i++) { for (j=0; j<clusteredData[i].rows(); j++) { // count the number of points nbPoints++; // for all other clusters and all points in these clusters for (k=i+1; k<nbClusters; k++) { for (l=0; l<clusteredData[k].rows(); l++) { index+=dist.apply(clusteredData[i].getRow(j), clusteredData[k].getRow(l))* dist.apply(centroids.getRow(i),centroids.getRow(k)); } } } } double m=0.5*(nbPoints*(nbPoints-1)); index=index/m; return true; }
double clusteringValidity::getMaximumDistance(const dmatrix& m1, const dmatrix& m2) const { int i,j; dmatrix distances(m1.rows(),m2.rows()); l2Distance<double> dist; for (i=0; i<m1.rows(); i++) { for (j=0; j<m2.rows(); j++) { distances[i][j]=dist.apply(m1.getRow(i),m2.getRow(j)); } } return distances.maximum(); }
double clusteringValidity::getAverageDistance(const dmatrix& m1, const dmatrix& m2) const { double distance=0.0; int i,j; l2Distance<double> dist; for (i=0; i<m1.rows(); i++) { for (j=0; j<m2.rows(); j++) { distance+=dist.apply(m1.getRow(i),m2.getRow(j)); } } distance=distance/((double)m1.rows()*(double)m2.rows()); return distance; }
/** * Adds an object to this classifier. The id is determined automatically * and returned in the parameter. */ bool shClassifier::trainObject(const dmatrix& input, int& id) { id=0; for (std::map<int,int>::const_iterator i=rIdMap.begin(); i != rIdMap.end(); i++) { if (i->second >= id) { id=i->second+1; } } idMap[id]=nClasses; rIdMap[nClasses]=id; nClasses++; const parameters& par=getParameters(); // do not touch min and max if (getParameters().binVector.size() > 0) { models.push_back(new sparseHistogram(getParameters().binVector, par.minimum,par.maximum)); } else { models.push_back(new sparseHistogram(getParameters().numberOfBins, par.minimum,par.maximum)); } // fill histograms int sum=0; for (int j=0; j<input.rows(); j++) { models[nClasses-1]->add(input.getRow(j)); sum++; } models[nClasses-1]->divide(static_cast<float>(sum)); defineOutputTemplate(); return true; }
double clusteringValidity::getCentroidDistance(const dmatrix& m1, const dmatrix& m2) const { l2Distance<double> dist; int i; dvector a(m1.columns()); dvector b(m2.columns()); for (i=0; i<m1.rows();i++) { a.add(m1.getRow(i)); } a.divide(m1.rows()); for (i=0; i<m2.rows();i++) { b.add(m2.getRow(i)); } b.divide(m2.rows()); return dist.apply(a,b); }
double clusteringValidity::getAverageToCentroidDiameter(const dmatrix& m1) const { dvector a(m1.columns()); int i,j; l2Distance<double> dist; double distance=0.0; for (i=0; i<m1.rows(); i++) { a.add(m1.getRow(i)); } a.divide(m1.rows()); for (j=0; j< m1.rows(); j++) { distance+=dist.apply(a,m1.getRow(j)); } if (m1.rows()>0) { return (2*distance/(double)m1.rows()); } else { return 2*distance; } }
double clusteringValidity::getStandardDiameter(const dmatrix& m1) const { dmatrix distances(m1.rows(),m1.rows()); int j,k; l2Distance<double> dist; for (j=0; j<m1.rows(); j++) { for (k=j+1; k<m1.rows(); k++) { distances[j][k]=dist.apply(m1.getRow(j), m1.getRow(k)); } } return distances.maximum(); }
// Calls the same method of the superclass. bool shClassifier::train(const dmatrix& input, const ivector& ids) { buildIdMaps(ids); boundsFunctor<double> bounds; const parameters& par=getParameters(); dvector min,max; if (par.autoBounds) { bounds.boundsOfRows(input,min,max); } else { min=par.minimum; max=par.maximum; } _lti_debug("Binvector.size = " << par.binVector.size() << "\n"); int i; // build one histogram per object models.resize(nClasses); for (i=0; i<nClasses; i++) { if (par.binVector.size() == min.size()) { models[i]=new sparseHistogram(par.binVector,min,max); } else { models[i]=new sparseHistogram(par.numberOfBins,min,max); } } ivector sum(nClasses); // fill histograms for (i=0; i<input.rows(); i++) { int id=idMap[ids.at(i)]; models[id]->add(input.getRow(i)); sum[id]++; } // normalize histograms for (i=0; i<nClasses; i++) { _lti_debug("Sum of " << i << " is " << sum.at(i) << "\n"); if (sum.at(i) == 0) { delete models[i]; models[i]=0; } else { models[i]->divide(static_cast<float>(sum.at(i))); } } defineOutputTemplate(); return true; }
bool daviesBouldinIndex::apply(const std::vector<dmatrix>& clusteredData, double& index, const dmatrix& centroids) const { int nbClusters=clusteredData.size(); int i,j; dvector interClusterDistance(nbClusters); l2Distance<double> dist; // compute the average inter cluster distance double distance; for (i=0; i<nbClusters; i++) { for (j=0; j<clusteredData[i].rows(); j++) { distance=dist.apply(clusteredData[i].getRow(j), centroids.getRow(i)); distance=distance*distance; interClusterDistance[i]+=distance; } if (clusteredData[i].rows()!=0) { interClusterDistance[i]=interClusterDistance[i]/ (double)clusteredData[i].rows();} interClusterDistance[i]=sqrt(interClusterDistance[i]); } dmatrix indices(nbClusters,nbClusters); for (i=0; i<nbClusters; i++) { for (j=i+1; j<nbClusters; j++) { double distance=dist.apply(centroids.getRow(i), centroids.getRow(j)); indices[i][j]=(interClusterDistance[i]+ interClusterDistance[j])/distance; indices[j][i]=indices[i][j]; } } index=0.0; for (i=0; i<nbClusters; i++) { index+=indices.getRow(i).maximum(); } index=index/(double)nbClusters; return true; }
double clusteringValidity::getAverageInterpointDistance(const dmatrix& m1, const dmatrix& m2) const { l2Distance<double> dist; int i; dvector a(m1.columns()); dvector b(m2.columns()); for (i=0; i<m1.rows();i++) { a.add(m1.getRow(i)); } a.divide(m1.rows()); // centroid 1 for (i=0; i<m2.rows();i++) { b.add(m2.getRow(i)); } b.divide(m2.rows()); // centroid 2 double distance=0.0; for (i=0; i<m1.rows(); i++) { distance+=dist.apply(m1.getRow(i),a); } for (i=0; i<m2.rows(); i++) { distance+=dist.apply(m2.getRow(i),b); } return (distance/(m1.rows()+m2.rows())); }
double clusteringValidity::getAverageDiameter(const dmatrix& m1) const { double distance=0.0; int j,k; l2Distance<double> dist; for (j=0; j<m1.rows(); j++) { for (k=0; k<m1.rows(); k++) { distance+=dist.apply(m1.getRow(j), m1.getRow(k)); } } if (m1.rows()>1) { return (distance/((double)m1.rows()* (double)(m1.rows()-1))); } else { return distance; } }
/* * compute the error of the given weights for the whole training set. */ bool MLP::computeTotalError(const std::vector<dmatrix>& mWeights, const dmatrix& inputs, const ivector& ids, double& totalError) const { if (ids.size() != inputs.rows()) { return false; } const parameters& param = getParameters(); const int layers = param.hiddenUnits.size()+1; std::vector<dvector> uNet(layers),uOut(layers); int i; double tmp; totalError=0.0; for (i=0;i<ids.size();++i) { propagate(inputs.getRow(i),mWeights,uNet,uOut); computePatternError(ids.at(i),uOut.back(),tmp); totalError+=tmp; } return true; }
bool dunnIndex::apply(const std::vector<dmatrix>& clusteredData, double& index, const dmatrix& centroids) const { int nbClusters=clusteredData.size(); double denominator=0.0; int i,j; l2Distance<double> dist; dvector diameters(nbClusters); parameters param; param=getParameters(); // pointer to the function which implements the measure according to the // parameters double (lti::clusteringValidity::*diamFunc)(const dmatrix&) const; #ifdef _LTI_MSC_DOT_NET_2003 // nasty bug in this version of the .NET compiler #define QUALIFIER #else #define QUALIFIER <i::dunnIndex:: #endif switch (param.diameterMeasure) { case parameters::Standard: diamFunc=QUALIFIER getStandardDiameter; break; case parameters::Average: diamFunc=QUALIFIER getAverageDiameter; break; case parameters::Centroid: diamFunc=QUALIFIER getAverageToCentroidDiameter; break; default: diamFunc=QUALIFIER getStandardDiameter; setStatusString("Unknown diameterMeasure in clusteringValidity\n"); return false; } // compute all diameters of all clusters for (i=0; i<nbClusters; i++) { diameters[i]=(this->*diamFunc)(clusteredData[i]); } denominator=diameters.maximum(); // pointer to the function which calculates the distance of the functions // a pointer to a function is used, because the function will be called // many times later double (lti::clusteringValidity::*distFunc) (const dmatrix&,const dmatrix&) const ; // set pointer to function which is set by the parameter distanceMeasure switch (param.distanceMeasure) { case parameters::Minimum: distFunc=QUALIFIER getMinimumDistance; break; case parameters::Maximum: distFunc=QUALIFIER getMaximumDistance; break; case parameters::Mean: distFunc=QUALIFIER getAverageDistance; break; case parameters::Centroids: distFunc=QUALIFIER getCentroidDistance; break; case parameters::Interpoint: distFunc=QUALIFIER getAverageInterpointDistance; break; default: distFunc=QUALIFIER getAverageDistance; setStatusString("Unknown distanceMeasure in clusteringValidity\n"); return false; } // compute the distances of all clusters to each other int counter=0; dvector distanceVector(static_cast<int>(.5*(nbClusters*(nbClusters-1)))); for (i=0; i<nbClusters; i++) { for (j=i+1; j<nbClusters; j++) { if (distFunc==QUALIFIER getCentroidDistance) { distanceVector[counter]=dist.apply(centroids.getRow(i), centroids.getRow(j)); } else { distanceVector[counter]=(this->*distFunc)(clusteredData[i], clusteredData[j]); } counter++; } } distanceVector.divide(denominator); index=distanceVector.minimum(); return true; }
bool MLP::trainSteepestSequential(const dmatrix& data, const ivector& internalIds) { const parameters& param = getParameters(); char buffer[256]; bool abort = false; scramble<int> scrambler; int i,j,k; double tmpError; ivector idx; idx.resize(data.rows(),0,false,false); for (i=0;i<idx.size();++i) { idx.at(i)=i; } if (param.momentum > 0) { // with momentum dvector grad,delta(weights.size(),0.0); for (i=0; !abort && (i<param.maxNumberOfEpochs); ++i) { scrambler.apply(idx); // present the pattern in a random sequence totalError = 0; for (j=0;j<idx.size();++j) { k=idx.at(j); calcGradient(data.getRow(k),internalIds.at(k),grad); computeActualError(internalIds.at(k),tmpError); totalError+=tmpError; delta.addScaled(param.learnrate,grad,param.momentum,delta); weights.add(delta); } // update progress info object if (validProgressObject()) { sprintf(buffer,"Error=%f",totalError/errorNorm); getProgressObject().step(buffer); abort = abort || (totalError/errorNorm <= param.stopError); abort = abort || getProgressObject().breakRequested(); } } } else { // without momentum ivector idx; idx.resize(data.rows(),0,false,false); dvector grad; int i,j,k; double tmpError; for (i=0;i<idx.size();++i) { idx.at(i)=i; } for (i=0; !abort && (i<param.maxNumberOfEpochs); ++i) { scrambler.apply(idx); // present the pattern in a random sequence totalError = 0; for (j=0;j<idx.size();++j) { k=idx.at(j); calcGradient(data.getRow(k),internalIds.at(k),grad); computeActualError(internalIds.at(k),tmpError); totalError+=tmpError; weights.addScaled(param.learnrate,grad); } // update progress info object if (validProgressObject()) { sprintf(buffer,"Error=%f",totalError/errorNorm); getProgressObject().step(buffer); abort = abort || (totalError/errorNorm <= param.stopError); abort = abort || getProgressObject().breakRequested(); } } } return true; }
bool SOFM2D::trainDot(const dmatrix& data) { bool b=true; int i,j,k,maxN; int startx, starty, stopx, stopy; kernel2D<double> facN; l2Distance<double> dist; l2Distance<double>::parameters dfp; dfp.rowWise=true; dist.setParameters(dfp); const parameters& param=getParameters(); int step=0; int epoch; scramble<int> mix; ivector idx(data.rows()); for (i=0; i<data.rows(); i++) { idx[i]=i; } dvector prod; dvector sum; int winner; //normalize grid dvector norms; b = b && dist.apply(grid,norms); for (i=0; i<grid.rows(); i++) { grid.getRow(i).divide(norms[i]); } // temp value needed for kernel init const double tfac=sqrt(-2*log(param.orderNeighborThresh)); char buffer[256]; bool abort=false; //ordering for (epoch=0; epoch<param.stepsOrdering; epoch++) { if (validProgressObject()) { sprintf(buffer,"ordering step %i",epoch); getProgressObject().step(buffer); abort = getProgressObject().breakRequested(); } if (abort) return b; mix.apply(idx); for (i=0; i<idx.size(); i++, step++) { const dvector& curr = data.getRow(idx[i]); //find winner grid.multiply(curr, prod); winner=prod.getIndexOfMaximum(); //find size and init neighborhood function maxN=static_cast<int>(sigma*tfac); getNeighborhoodKernel(maxN, facN); //find bounds if (winner%sizeX-maxN < 0) { startx=-winner%sizeX; } else { startx=-maxN; } if (winner%sizeX+maxN > sizeX) { stopx=sizeX-winner%sizeX; } else { stopx=maxN; } if (winner/sizeX-maxN < 0) { starty=-winner/sizeX; } else { starty=-maxN; } if (winner/sizeX+maxN > sizeY) { stopy=sizeY-winner/sizeX; } else { stopy=maxN; } for (j=starty; j<stopy; j++) { for (k=startx; k<stopx; k++) { if (facN.at(j,k)==0.) { continue; } dvector& winnerRow=grid[winner+j*sizeX+k]; winnerRow.addScaled(lrOrder*facN.at(j,k), curr); winnerRow.divide(dist.apply(winnerRow)); } } lrOrder-=lrOrderDelta; sigma-=sigmaDelta; } } // convergence training // neighborhood is fixed: calc matrix of factors. maxN=static_cast<int>(sigma*tfac); getNeighborhoodKernel(maxN, facN); double lrC=lrConvergeA/lrConvergeB; step=0; for (epoch=0; epoch<param.stepsConvergence; epoch++) { if (validProgressObject()) { sprintf(buffer,"convergence step %i",epoch); getProgressObject().step(buffer); abort = getProgressObject().breakRequested(); } if (abort) return b; mix.apply(idx); for (i=0; i<idx.size(); i++, step++) { const dvector& curr = data.getRow(idx[i]); //find winner grid.multiply(curr, prod); winner=prod.getIndexOfMaximum(); //find bounds if (winner%sizeX-maxN < 0) { startx=-winner%sizeX; } else { startx=-maxN; } if (winner%sizeX+maxN > sizeX) { stopx=sizeX-winner%sizeX; } else { stopx=maxN; } if (winner/sizeX-maxN < 0) { starty=-winner/sizeX; } else { starty=-maxN; } if (winner/sizeX+maxN > sizeY) { stopy=sizeY-winner/sizeX; } else { stopy=maxN; } for (j=starty; j<stopy; j++) { for (k=startx; k<stopx; k++) { if (facN.at(j,k)==0.) { continue; } dvector& winnerRow=grid[winner+j*sizeX+k]; winnerRow.addScaled(lrC*facN.at(j,k), curr); winnerRow.divide(dist.apply(winnerRow)); } } lrC=lrConvergeA/(step+lrConvergeB); } } return b; }
bool normModHubertStat::apply(const std::vector<dmatrix>& clusteredData, double& index, const dmatrix& centroids) const { index =0.0; int nbClusters=clusteredData.size(); l2Distance<double> dist; int nbPoints=0; int i,j,k,l; // count the points that are in clusteredData for (i=0; i<nbClusters; i++) { nbPoints+=clusteredData[i].rows(); } // x is the distance matrix. It has in the i-th rows and j-th column // the distance between the i-th and j-th point // y is an other distance matrix. It has in the i-th row and j-th column // the distance of the centroids of the clusters they belong to. dmatrix x(nbPoints,nbPoints); dmatrix y(nbPoints,nbPoints); int row=0; int col=0; for (i=0; i<nbClusters; i++) { for (j=0; j<clusteredData[i].rows(); j++) { for (k=0; k<nbClusters; k++) { for (l=0; l<clusteredData[k].rows(); l++) { if (col>row) { y.at(row,col)=dist.apply(centroids.getRow(i), centroids.getRow(k)); x.at(row,col)=dist.apply(clusteredData[i].getRow(j), clusteredData[k].getRow(l)); } if (col<nbPoints-1) col++; else { col=0; row++; } } } } } double m=0.5*(nbPoints*(nbPoints-1)); double meanX=x.sumOfElements()/m; double meanY=y.sumOfElements()/m; double tmp1=meanX*meanX; double tmp2=meanY*meanY; double varianzX=0.0; double varianzY=0.0; for (i=0; i<nbPoints; i++) { for (j=i+1; j<nbPoints; j++) { varianzX+=x[i][j]*x[i][j]-tmp1; varianzY+=y[i][j]*y[i][j]-tmp2; } } varianzX=varianzX/m; varianzY=varianzY/m; varianzX=sqrt(varianzX); varianzY=sqrt(varianzY); double varianz=varianzX*varianzY; for (i=0; i<nbPoints; i++) { for (j=i+1; j<nbPoints; j++) { index+=(x[i][j]-meanX)*(y[i][j]-meanY); } } index=index/(m*varianz); return true; }
bool SOFM2D::trainDist(const dmatrix& data) { bool b=true; int i,j,k,maxN; int startx, starty, stopx, stopy; kernel2D<double> facN; const parameters& param=getParameters(); distanceFunctor<double>* dist = 0; if (param.metricType == parameters::L1) { dist = new l1Distance<double>(); } else { dist = new l2Distance<double>(); } distanceFunctor<double>::parameters dfp; dfp.rowWise=true; dist->setParameters(dfp); int step=0; int epoch; scramble<int> mix; ivector idx(data.rows()); for (i=0; i<data.rows(); i++) { idx[i]=i; } dvector distances; dvector delta; int winner; char buffer[256]; bool abort=false; // temp value needed for kernel init const double tfac=sqrt(-2*log(param.orderNeighborThresh)); //ordering for (epoch=0; epoch<param.stepsOrdering; epoch++) { if (validProgressObject()) { sprintf(buffer,"ordering step %i",epoch); getProgressObject().step(buffer); abort = getProgressObject().breakRequested(); } if (abort) return b; mix.apply(idx); for (i=0; i<idx.size(); i++, step++) { const dvector& curr = data.getRow(idx[i]); dist->apply(grid, curr, distances); winner=distances.getIndexOfMinimum(); maxN=static_cast<int>(sigma*tfac); getNeighborhoodKernel(maxN, facN); //find bounds if (winner%sizeX-maxN < 0) { startx=-winner%sizeX; } else { startx=-maxN; } if (winner%sizeX+maxN > sizeX) { stopx=sizeX-winner%sizeX; } else { stopx=maxN; } if (winner/sizeX-maxN < 0) { starty=-winner/sizeX; } else { starty=-maxN; } if (winner/sizeX+maxN > sizeY) { stopy=sizeY-winner/sizeX; } else { stopy=maxN; } for (j=starty; j<stopy; j++) { for (k=startx; k<stopx; k++) { if (facN.at(j,k)==0.) { continue; } delta.subtract(curr, grid[winner+j*sizeX+k]); grid[winner+j*sizeX+k].addScaled(lrOrder*facN.at(j,k),delta); } } lrOrder-=lrOrderDelta; sigma-=sigmaDelta; } } // convergence training // neighborhood is fixed: calc matrix of factors. maxN=static_cast<int>(sigma*tfac); getNeighborhoodKernel(maxN, facN); double lrC=lrConvergeA/lrConvergeB; step=0; for (epoch=0; epoch<param.stepsConvergence; epoch++) { if (validProgressObject()) { sprintf(buffer,"convergence step %i",epoch); getProgressObject().step(buffer); abort = getProgressObject().breakRequested(); } if (abort) return b; mix.apply(idx); for (i=0; i<idx.size(); i++, step++) { const dvector& curr = data.getRow(idx[i]); //find winner dist->apply(grid, curr, distances); winner=distances.getIndexOfMinimum(); //find bounds if (winner%sizeX-maxN < 0) { startx=-winner%sizeX; } else { startx=-maxN; } if (winner%sizeX+maxN > sizeX) { stopx=sizeX-winner%sizeX; } else { stopx=maxN; } if (winner/sizeX-maxN < 0) { starty=-winner/sizeX; } else { starty=-maxN; } if (winner/sizeX+maxN > sizeY) { stopy=sizeY-winner/sizeX; } else { stopy=maxN; } for (j=starty; j<stopy; j++) { for (k=startx; k<stopx; k++) { if (facN.at(j,k)==0.) { continue; } delta.subtract(curr, grid[winner+j*sizeX+k]); grid[winner+j*sizeX+k].addScaled(lrC*facN.at(j,k),delta); } } lrC=lrConvergeA/(step+lrConvergeB); } } delete dist; return b; }
// implements the Fuzzy C Means algorithm bool fuzzyCMeans::train(const dmatrix& data) { bool ok=true; int t=0; // create the distance functor according to the paramter norm distanceFunctor<double>* distFunc = 0; switch (getParameters().norm) { case parameters::L1: distFunc = new l1Distance<double>; break; case parameters::L2: distFunc = new l2Distance<double>; break; default: break; } int nbOfClusters=getParameters().nbOfClusters; int nbOfPoints=data.rows(); if(nbOfClusters>nbOfPoints) { setStatusString("more Clusters than points"); ok = false; } double q=getParameters().fuzzifier; if (q<=1) { setStatusString("q has to be bigger than 1"); ok = false; } // select some points of the given data to initialise the centroids selectRandomPoints(data,nbOfClusters,centroids); // initialize variables centroids.resize(nbOfClusters,data.columns(),0.0); dmatrix memberships(nbOfPoints, nbOfClusters, 0.0); double terminationCriterion=0; double newDistance; dvector newCenter(data.columns()); dvector currentPoint(data.columns()); dmatrix newCentroids(nbOfClusters,data.columns(),0.0); double sumOfMemberships=0; double membership=0; double dist1; double dist2; int i,j,k,m; do { // calculate new memberships memberships.fill(0.0); // clear old memberships for (i=0; i<nbOfPoints; i++) { for (j=0; j<nbOfClusters; j++) { newDistance=0; dist1=distFunc->apply(data.getRow(i), centroids.getRow(j)); for (k=0; k<nbOfClusters; k++) { dist2=distFunc->apply(data.getRow(i), centroids.getRow(k)); // if distance is 0, normal calculation of membership is not possible. if (dist2!=0) { newDistance+=pow((dist1/dist2),(1/(q-1))); } } // if point and centroid are equal if (newDistance!=0) memberships.at(i,j)=1/newDistance; else { dvector row(memberships.columns(),0.0); memberships.setRow(i,row); memberships.at(i,j)=1; break; } } } t++; // counts the iterations // calculate new centroids based on modified memberships for (m=0; m<nbOfClusters; m++) { newCenter.fill(0.0); sumOfMemberships=0; for (i=0; i<nbOfPoints; i++) { currentPoint=data.getRow(i); membership=pow(memberships.at(i,m),q); sumOfMemberships+=membership; currentPoint.multiply(membership); newCenter.add(currentPoint); } newCenter.divide(sumOfMemberships); newCentroids.setRow(m,newCenter); } terminationCriterion=distFunc->apply(centroids,newCentroids); centroids=newCentroids; } // the termination criterions while ( (terminationCriterion>getParameters().epsilon) && (t<getParameters().maxIterations)); int nbClusters = nbOfClusters; //Put the id information into the result object //Each cluster has the id of its position in the matrix ivector tids(nbClusters); for (i=0; i<nbClusters; i++) { tids.at(i)=i; } outTemplate=outputTemplate(tids); return ok; }
bool sffs::apply(const dmatrix& src,const ivector& srcIds, dmatrix& dest) const { bool ok=true; dest.clear(); parameters param=getParameters(); // initialize cross validator costFunction *cF; cF = param.usedCostFunction; cF->setSrc(src,srcIds); int featureToInsert(0),featureToDelete(0),i; double oldRate,newRate; bool doInclude=true; bool terminate=false; int nbFeatures=src.columns(); std::list<int> in,out; std::list<int>::iterator it; std::map<double,int> values; double value; for (i=0; i<nbFeatures; i++) { out.push_back(i); } ivector posInSrc(nbFeatures,-1);//saves the position in src of the inserted // feature to mark it as not used if this feature is deleted later dvector regRate(nbFeatures); // the recognition rates after the insertion // of a new feature if (param.nbFeatures<2) { setStatusString("You will have to choose at least two features. Set nbFeatures=2"); return false; } // add the first best two features; do 2 steps sfs for (i=0; i<2; i++ ) { if (dest.columns()<src.columns() && !terminate) { // add space for one extra feature for (it=out.begin(); it!=out.end(); it++) { in.push_back(*it); cF->apply(in,value); values[value]=*it; in.pop_back(); } // search for maximum in regRate; all possibilities not tested are -1 in.push_back((--values.end())->second); out.remove((--values.end())->second); } } cF->apply(in,oldRate); while (!terminate) { // STEP 1: include the best possible feature if (static_cast<int>(in.size())<src.columns() && !terminate && doInclude) { values.clear(); for (it=out.begin(); it!=out.end(); it++) { in.push_back(*it); cF->apply(in,value); values[value]=*it; in.pop_back(); } featureToInsert=(--values.end())->second; in.push_back(featureToInsert); out.remove(featureToInsert); } // STEP 2: conditional exclusion if (in.size()>0 && !terminate) { values.clear(); for (it=in.begin(); it!=in.end(); it++) { int tmp=*it; it=in.erase(it); cF->apply(in,value); values[value]=tmp; in.insert(it,tmp); it--; } featureToDelete=(--values.end())->second; // if the least significant feature is equal to the most significant // feature that was included in step 1, leave feature and // include the next one if (featureToDelete==featureToInsert) { doInclude=true; } else { // delete this feature and compute new recognition rate // if the feature to delete is not the last feature in dest, // change the feature against the last feature in dest and delete // the last column in dest, otherwise if the feature to delete // is equal to the last feature in dest nothing will be done, // because this is already the lacking feature in temp cF->apply(in,newRate); // if recognition rate without least significant feature is better // than with this feature delete it if (newRate>oldRate) { in.remove(featureToDelete); out.push_back(featureToDelete); // search for another least significant feature before // including the next one doInclude=false; oldRate=newRate; } else { doInclude=true; } // if only two features left, include the next one if (dest.columns()<=2) { doInclude=true; } } } // end of exclusion // test if the predetermined number of features is reached terminate=(param.nbFeatures==static_cast<int>(in.size())); } // while (!terminate) // Now fill dest const int sz = static_cast<int>(in.size()); dest.resize(src.rows(), sz, 0., false, false); ivector idvec(false, sz); std::list<int>::const_iterator lit = in.begin(); for (i=0; i < sz; ++i) { idvec.at(i)=*lit; ++lit; } for (i=0; i < src.rows(); ++i) { const dvector& svec = src.getRow(i); dvector& dvec = dest.getRow(i); for (int j=0; j < sz; ++j) { dvec.at(j) = svec.at(idvec.at(j)); } } return ok; };