У меня есть приложение, в котором мне нужно самому реализовать K-means. Я пробовал свою реализацию в небольшой программе, чтобы посмотреть, как идут дела; однако меня действительно сбивает с толку то, что каждый раз при запуске программы я получаю одни и те же центры кластеров. Я удивлен, потому что мои центры кластеров инициализируются случайным образом, и я использую FLANN для обновления кластеров (оба должны сделать вывод недетерминированным c, верно?). Я, наверное, что-то упускаю и буду признателен за помощь.
cv::Mat kMeans(cv::Mat data, int k, int max_itr){
cv::Mat centroids = cv::Mat(cv::Size(data.cols, k), data.type());
std::vector<int> cluster_ids(data.rows, 0);
//randomly initialize centroids
for(int i = 0; i < k; i++)
{
int idx = rand() % data.rows;
data.row(idx).copyTo(centroids.row(i));
}
int itr = 0;
cv::flann::Index kdtree(centroids, cv::flann::KDTreeIndexParams(4));
cv::Mat indices, dists;
//TODO: add tolerance stopping condition
while (itr < max_itr)
{
//assign data points to centroids
for(int i = 0; i < data.rows; i++)
{
kdtree.knnSearch(data.row(i), indices, dists, 1, cv::flann::SearchParams(32));
cluster_ids[i] = indices.data[0];
}
//update centroids
for(int i = 0; i < centroids.rows; i++)
{
cv::Mat sum = cv::Mat::zeros(cv::Size(data.cols, 1), data.type());
int count = 0;
for(int j = 0; j < data.rows; j++)
{
if(cluster_ids[j] != i) {continue;}
sum += data.row(j);
count++;
}
centroids.row(i) = sum / float(count);
}
itr += 1;
}
return centroids;
}
int main()
{
cv::Mat_<float> data;
cv::Mat_<float> centroids;
cv::Mat dst;
//initialize with dummy data
for(int i = 0; i < 1000; i++)
{
cv::Mat row = (cv::Mat_<float>(1, 3) << float(i), float(i), float(i));
data.push_back(row);
}
centroids = kMeans(data, 20, 20);
std::cout << centroids << std::endl;
return 0;
}