【web搜索】学习笔记-k-means聚类

k-means聚类也称k均值算法,自顶而下的聚类算法,根据元素对类的所属是否为而至,又分为硬聚类和软聚类。
在普通的k均值算法中,元素和类用相同的向量形式表达。类是质心,即类中所有元素的均值,初始时可将元素随意(或根据启发性信息)分为k个组,计算出各个组的之心,然后按照以下的算法进行类间元素的调整:

在这里插入图片描述

在这里插入图片描述

硬k均值聚类算法

1  初始化k个组的质心向量
2  while 还可以继续改进 do
3 	for 每个元素(文档)d do
4 		找出质心向量与d最相似的组c
5 		将d调整到组c之中
6 	end for
7 	for 每个组c do
8 		重新计算质心向量
9 	end for
10 end while

软k均值聚类算法
相对于硬k均值聚类,删去3-6步,在第8步计算质心向量时,采用下式计算质心偏移量,注意:每个元素对每个组的偏移量都有贡献, 但贡献的大小不同,离组的质心越近,贡献越大。

在这里插入图片描述

在这里插入图片描述

相关链接:K-means聚类算法原理和C++实现

学习笔记:
先附上上一段链接中的代码:

#include "stdafx.h"
#include<iostream>
#include<cmath>
#include<vector>
#include<ctime>
using namespace std;
typedef unsigned int uint;

struct Cluster
{
	vector<double> centroid;
	vector<uint> samples;
};
double cal_distance(vector<double> a, vector<double> b)
{
	uint da = a.size();
	uint db = b.size();
	if (da != db) cerr << "Dimensions of two vectors must be same!!\n";
	double val = 0.0;
	for (uint i = 0; i < da; i++)
	{
		val += pow((a[i] - b[i]), 2);
	}
	return pow(val, 0.5);
}
vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches)
{
	const uint row_num = trainX.size();
	const uint col_num = trainX[0].size();

	/*初始化聚类中心*/
	vector<Cluster> clusters(k);
	uint seed = (uint)time(NULL);
	for (uint i = 0; i < k; i++)
	{
		srand(seed);
		int c = rand() % row_num;
		clusters[i].centroid = trainX[c];
		seed = rand();
	}

	/*多次迭代直至收敛,本次试验迭代100次*/
	for (uint it = 0; it < maxepoches; it++)
	{
		/*每一次重新计算样本点所属类别之前,清空原来样本点信息*/
		for (uint i = 0; i < k; i++)
		{
			clusters[i].samples.clear();
		}
		/*求出每个样本点距应该属于哪一个聚类*/
		for (uint j = 0; j < row_num; j++)
		{
			/*都初始化属于第0个聚类*/
			uint c = 0;
			double min_distance = cal_distance(trainX[j], clusters[c].centroid);
			for (uint i = 1; i < k; i++)
			{
				double distance = cal_distance(trainX[j], clusters[i].centroid);
				if (distance < min_distance)
				{
					min_distance = distance;
					c = i;
				}
			}
			clusters[c].samples.push_back(j);
		}

		/*更新聚类中心*/
		for (uint i = 0; i < k; i++)
		{
			vector<double> val(col_num, 0.0);
			for (uint j = 0; j < clusters[i].samples.size(); j++)
			{
				uint sample = clusters[i].samples[j];
				for (uint d = 0; d < col_num; d++)
				{
					val[d] += trainX[sample][d];
					if (j == clusters[i].samples.size() - 1)
						clusters[i].centroid[d] = val[d] / clusters[i].samples.size();
				}
			}
		}
	}
	return clusters;
}

int main()
{
	vector<vector<double> > trainX(9, vector<double>(1, 0));
	//对9个数据{1 2 3 11 12 13 21 22 23}聚类
	double data = 1.0;
	for (uint i = 0; i < 9; i++)
	{
		trainX[i][0] = data;
		if ((i + 1) % 3 == 0) data += 8;
		else data++;
	}

	/*k-means聚类*/
	vector<Cluster> clusters_out = k_means(trainX, 3, 100);

	/*输出分类结果*/
	for (uint i = 0; i < clusters_out.size(); i++)
	{
		cout << "Cluster " << i << " :" << endl;

		/*子类中心*/
		cout << "\t" << "Centroid: " << "\n\t\t[ ";
		for (uint j = 0; j < clusters_out[i].centroid.size(); j++)
		{
			cout << clusters_out[i].centroid[j] << " ";
		}
		cout << "]" << endl;

		/*子类样本点*/
		cout << "\t" << "Samples:\n";
		for (uint k = 0; k < clusters_out[i].samples.size(); k++)
		{
			uint c = clusters_out[i].samples[k];
			cout << "\t\t[ ";
			for (uint m = 0; m < trainX[0].size(); m++)
			{
				cout << trainX[c][m] << " ";
			}
			cout << "]\n";
		}
	}
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
代码理解:
定义结构体Cluster,含有double类型向量centroid和uint类型向量samples
对数据 vector<vector > trainX(9, vector(1, 0))赋初值
调用函数k_means进行k-means聚类
输出分类结果

详细理解函数:

vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches)
//返回类型为分类向量,输入参数分别为数据、设定分类数与迭代次数
{
	计算训练数据矩阵的行(row_num)与列(col_num)(示例中为9*1);
	初始化聚类中心:随机分入k类中;
	迭代(这里最好优化成收敛,示例的迭代次数为100{
		每一次重新计算样本点所属类别之前,清空原来样本点信息;
		对每一个样本点(row_num),计算它与各类间距,判断其应属于哪一聚类;
		对每一类更新聚类中心
		{
			对此类中的每一个样本(clusters[i].samples.size)
			{
				对样本的每一列(col_num)
				{
					迭代计算此类的样本总值;
					若到达此类的最后一个样本(j == clusters[i].samples.size() - 1)
					计算均值;
				}
			}
		}
	}
	
}

缺陷:
在这里插入图片描述
由于失真函数是非凸函数,有可能陷入局部收敛,可以多运行几次k-means(采用不同的随机初始聚类中心),然后从多次结果中选出失真函数最小的聚类结果。参照上述链接。

发布了43 篇原创文章 · 获赞 4 · 访问量 1202

猜你喜欢

转载自blog.csdn.net/weixin_42176221/article/details/103428717