Refactor RefinedStart to give centroids not assignments.

This commit is contained in:
Ryan Curtin
2016-04-12 14:43:52 +00:00
parent a38608bea2
commit b8bb079a5f
2 changed files with 36 additions and 9 deletions
+17 -1
View File
@@ -43,7 +43,23 @@ class RefinedStart
/**
* Partition the given dataset into the given number of clusters according to
* the random sampling scheme outlined in Bradley and Fayyad's paper.
* the random sampling scheme outlined in Bradley and Fayyad's paper, and
* return centroids.
*
* @tparam MatType Type of data (arma::mat or arma::sp_mat).
* @param data Dataset to partition.
* @param clusters Number of clusters to split dataset into.
* @param centroids Matrix to store centroids into.
*/
template<typename MatType>
void Cluster(const MatType& data,
const size_t clusters,
arma::mat& centroids) const;
/**
* Partition the given dataset into the given number of clusters according to
* the random sampling scheme outlined in Bradley and Fayyad's paper, and
* return point assignments.
*
* @tparam MatType Type of data (arma::mat or arma::sp_mat).
* @param data Dataset to partition.
@@ -19,7 +19,7 @@ namespace kmeans {
template<typename MatType>
void RefinedStart::Cluster(const MatType& data,
const size_t clusters,
arma::Row<size_t>& assignments) const
arma::mat& centroids) const
{
// This will hold the sampled datasets.
const size_t numPoints = size_t(percentage * data.n_cols);
@@ -28,10 +28,6 @@ void RefinedStart::Cluster(const MatType& data,
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::Row<size_t> sampledAssignments;
arma::mat centroids;
for (size_t i = 0; i < samplings; ++i)
{
// First, assemble the sampled dataset.
@@ -55,7 +51,7 @@ void RefinedStart::Cluster(const MatType& data,
// 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<> kmeans;
kmeans.Cluster(sampledData, clusters, sampledAssignments, centroids);
kmeans.Cluster(sampledData, clusters, centroids);
// Store the sampled centroids.
sampledCentroids.cols(i * clusters, (i + 1) * clusters - 1) = centroids;
@@ -65,7 +61,18 @@ void RefinedStart::Cluster(const MatType& data,
// Now, we run k-means on the sampled centroids to get our final clusters.
KMeans<> kmeans;
kmeans.Cluster(sampledCentroids, clusters, sampledAssignments, centroids);
kmeans.Cluster(sampledCentroids, clusters, centroids);
}
template<typename MatType>
void RefinedStart::Cluster(const MatType& data,
const size_t clusters,
arma::Row<size_t>& assignments) const
{
// Perform the Bradley-Fayyad refined start algorithm, and get initial
// centroids back.
arma::mat centroids;
Cluster(data, clusters, centroids);
// Turn the final centroids into assignments.
assignments.set_size(data.n_cols);
@@ -77,7 +84,11 @@ void RefinedStart::Cluster(const MatType& data,
for (size_t j = 0; j < clusters; ++j)
{
const double distance = kmeans.Metric().Evaluate(data.col(i),
// This is restricted to the L2 distance, and unfortunately it would take
// a lot of refactoring and redesign to make this more general... we would
// probably need to have KMeans take a template template parameter for the
// initial partition policy. It's not clear how to best do this.
const double distance = metric::EuclideanDistance::Evaluate(data.col(i),
centroids.col(j));
if (distance < minDistance)