void permuteVector(const arma::Col<ValueType> &original, arma::Col<ValueType> &permuted) const { const int dim = original.n_elem; permuted.set_size(dim); for (int i = 0; i < dim; ++i) permuted(m_permutedIndices[i]) = original(i); }
void unpermuteVector(const arma::Col<ValueType> &permuted, arma::Col<ValueType> &original) const { const int dim = permuted.n_elem; original.set_size(dim); for (int i = 0; i < dim; ++i) original(i) = permuted(m_permutedIndices[i]); }
inline void HRectBound<MetricType, ElemType>::Center( arma::Col<ElemType>& center) const { // Set size correctly if necessary. if (!(center.n_elem == dim)) center.set_size(dim); for (size_t i = 0; i < dim; i++) center(i) = bounds[i].Mid(); }
double HMM<Distribution>::Predict(const arma::mat& dataSeq, arma::Col<size_t>& stateSeq) const { // This is an implementation of the Viterbi algorithm for finding the most // probable sequence of states to produce the observed data sequence. We // don't use log-likelihoods to save that little bit of time, but we'll // calculate the log-likelihood at the end of it all. stateSeq.set_size(dataSeq.n_cols); arma::mat logStateProb(transition.n_rows, dataSeq.n_cols); arma::mat stateSeqBack(transition.n_rows, dataSeq.n_cols); // Store the logs of the transposed transition matrix. This is because we // will be using the rows of the transition matrix. arma::mat logTrans(log(trans(transition))); // The calculation of the first state is slightly different; the probability // of the first state being state j is the maximum probability that the state // came to be j from another state. logStateProb.col(0).zeros(); for (size_t state = 0; state < transition.n_rows; state++) { logStateProb(state, 0) = log(initial[state] * emission[state].Probability(dataSeq.unsafe_col(0))); stateSeqBack(state, 0) = state; } // Store the best first state. arma::uword index; for (size_t t = 1; t < dataSeq.n_cols; t++) { // Assemble the state probability for this element. // Given that we are in state j, we use state with the highest probability // of being the previous state. for (size_t j = 0; j < transition.n_rows; j++) { arma::vec prob = logStateProb.col(t - 1) + logTrans.col(j); logStateProb(j, t) = prob.max(index) + log(emission[j].Probability(dataSeq.unsafe_col(t))); stateSeqBack(j, t) = index; } } // Backtrack to find the most probable state sequence. logStateProb.unsafe_col(dataSeq.n_cols - 1).max(index); stateSeq[dataSeq.n_cols - 1] = index; for (size_t t = 2; t <= dataSeq.n_cols; t++) stateSeq[dataSeq.n_cols - t] = stateSeqBack(stateSeq[dataSeq.n_cols - t + 1], dataSeq.n_cols - t + 1); return logStateProb(stateSeq(dataSeq.n_cols - 1), dataSeq.n_cols - 1); }
void NaiveBayesClassifier<MatType>::Classify(const MatType& data, arma::Col<size_t>& results) { // Check that the number of features in the test data is same as in the // training data. Log::Assert(data.n_rows == means.n_rows); arma::vec probs = arma::log(probabilities); arma::mat invVar = 1.0 / variances; arma::mat testProbs = arma::repmat(probs.t(), data.n_cols, 1); results.set_size(data.n_cols); // No need to fill with anything yet. Log::Info << "Running Naive Bayes classifier on " << data.n_cols << " data points with " << data.n_rows << " features each." << std::endl; // Calculate the joint probability for each of the data points for each of the // means.n_cols. // Loop over every class. for (size_t i = 0; i < means.n_cols; i++) { // This is an adaptation of gmm::phi() for the case where the covariance is // a diagonal matrix. arma::mat diffs = data - arma::repmat(means.col(i), 1, data.n_cols); arma::mat rhs = -0.5 * arma::diagmat(invVar.col(i)) * diffs; arma::vec exponents(diffs.n_cols); for (size_t j = 0; j < diffs.n_cols; ++j) exponents(j) = std::exp(arma::accu(diffs.col(j) % rhs.unsafe_col(j))); testProbs.col(i) += log(pow(2 * M_PI, (double) data.n_rows / -2.0) * pow(det(arma::diagmat(invVar.col(i))), -0.5) * exponents); } // Now calculate the label. for (size_t i = 0; i < data.n_cols; ++i) { // Find the index of the class with maximum probability for this point. arma::uword maxIndex = 0; arma::vec pointProbs = testProbs.row(i).t(); pointProbs.max(maxIndex); results[i] = maxIndex; } return; }
void HMM<Distribution>::Generate(const size_t length, arma::mat& dataSequence, arma::Col<size_t>& stateSequence, const size_t startState) const { // Set vectors to the right size. stateSequence.set_size(length); dataSequence.set_size(dimensionality, length); // Set start state (default is 0). stateSequence[0] = startState; // Choose first emission state. double randValue = math::Random(); // We just have to find where our random value sits in the probability // distribution of emissions for our starting state. dataSequence.col(0) = emission[startState].Random(); // Now choose the states and emissions for the rest of the sequence. for (size_t t = 1; t < length; t++) { // First choose the hidden state. randValue = math::Random(); // Now find where our random value sits in the probability distribution of // state changes. double probSum = 0; for (size_t st = 0; st < transition.n_rows; st++) { probSum += transition(st, stateSequence[t - 1]); if (randValue <= probSum) { stateSequence[t] = st; break; } } // Now choose the emission. dataSequence.col(t) = emission[stateSequence[t]].Random(); } }
void GMM<FittingType>::Classify(const arma::mat& observations, arma::Col<size_t>& labels) const { // This is not the best way to do this! // We should not have to fill this with values, because each one should be // overwritten. labels.set_size(observations.n_cols); for (size_t i = 0; i < observations.n_cols; ++i) { // Find maximum probability component. double probability = 0; for (size_t j = 0; j < gaussians; ++j) { double newProb = Probability(observations.unsafe_col(i), j); if (newProb >= probability) { probability = newProb; labels[i] = j; } } } }
inline void MeanShift<UseKernel, KernelType, MatType>::Cluster( const MatType& data, arma::Col<size_t>& assignments, arma::mat& centroids, bool useSeeds) { if (radius <= 0) { // An invalid radius is given; an estimation is needed. Radius(EstimateRadius(data)); } MatType seeds; const MatType* pSeeds = &data; if (useSeeds) { GenSeeds(data, radius, 1, seeds); pSeeds = &seeds; } // Holds all centroids before removing duplicate ones. arma::mat allCentroids(pSeeds->n_rows, pSeeds->n_cols); assignments.set_size(data.n_cols); range::RangeSearch<> rangeSearcher(data); math::Range validRadius(0, radius); std::vector<std::vector<size_t> > neighbors; std::vector<std::vector<double> > distances; // For each seed, perform mean shift algorithm. for (size_t i = 0; i < pSeeds->n_cols; ++i) { // Initial centroid is the seed itself. allCentroids.col(i) = pSeeds->unsafe_col(i); for (size_t completedIterations = 0; completedIterations < maxIterations; completedIterations++) { // Store new centroid in this. arma::colvec newCentroid = arma::zeros<arma::colvec>(pSeeds->n_rows); rangeSearcher.Search(allCentroids.unsafe_col(i), validRadius, neighbors, distances); if (neighbors[0].size() <= 1) break; // Calculate new centroid. if (!CalculateCentroid(data, neighbors[0], distances[0], newCentroid)) newCentroid = allCentroids.unsafe_col(i); // If the mean shift vector is small enough, it has converged. if (metric::EuclideanDistance::Evaluate(newCentroid, allCentroids.unsafe_col(i)) < 1e-3 * radius) { // Determine if the new centroid is duplicate with old ones. bool isDuplicated = false; for (size_t k = 0; k < centroids.n_cols; ++k) { const double distance = metric::EuclideanDistance::Evaluate( allCentroids.unsafe_col(i), centroids.unsafe_col(k)); if (distance < radius) { isDuplicated = true; break; } } if (!isDuplicated) centroids.insert_cols(centroids.n_cols, allCentroids.unsafe_col(i)); // Get out of the loop. break; } // Update the centroid. allCentroids.col(i) = newCentroid; } } // Assign centroids to each point. neighbor::KNN neighborSearcher(centroids); arma::mat neighborDistances; arma::Mat<size_t> resultingNeighbors; neighborSearcher.Search(data, 1, resultingNeighbors, neighborDistances); assignments = resultingNeighbors.t(); }
void RefinedStart::Cluster(const MatType& data, const size_t clusters, arma::Col<size_t>& assignments) const { math::RandomSeed(std::time(NULL)); // This will hold the sampled datasets. const size_t numPoints = size_t(percentage * data.n_cols); MatType sampledData(data.n_rows, numPoints); // vector<bool> is packed so each bool is 1 bit. std::vector<bool> pointsUsed(data.n_cols, false); arma::mat sampledCentroids(data.n_rows, samplings * clusters); // We will use these objects repeatedly for clustering. arma::Col<size_t> sampledAssignments; arma::mat centroids; KMeans<> kmeans; for (size_t i = 0; i < samplings; ++i) { // First, assemble the sampled dataset. size_t curSample = 0; while (curSample < numPoints) { // Pick a random point in [0, numPoints). size_t sample = (size_t) math::RandInt(data.n_cols); if (!pointsUsed[sample]) { // This point isn't used yet. So we'll put it in our sample. pointsUsed[sample] = true; sampledData.col(curSample) = data.col(sample); ++curSample; } } // Now, using the sampled dataset, run k-means. In the case of an empty // cluster, we re-initialize that cluster as the point furthest away from // the cluster with maximum variance. This is not *exactly* what the paper // implements, but it is quite similar, and we'll call it "good enough". kmeans.Cluster(sampledData, clusters, sampledAssignments, centroids); // Store the sampled centroids. sampledCentroids.cols(i * clusters, (i + 1) * clusters - 1) = centroids; pointsUsed.assign(data.n_cols, false); } // Now, we run k-means on the sampled centroids to get our final clusters. kmeans.Cluster(sampledCentroids, clusters, sampledAssignments, centroids); // Turn the final centroids into assignments. assignments.set_size(data.n_cols); for (size_t i = 0; i < data.n_cols; ++i) { // Find the closest centroid to this point. double minDistance = std::numeric_limits<double>::infinity(); size_t closestCluster = clusters; for (size_t j = 0; j < clusters; ++j) { const double distance = kmeans.Metric().Evaluate(data.col(i), centroids.col(j)); if (distance < minDistance) { minDistance = distance; closestCluster = j; } } // Assign the point to its closest cluster. assignments[i] = closestCluster; } }