由于此blog不能编辑数学公式,我只有写在word,然后在截图粘贴了。
上述即是我对k-means的理解,K均值法有很多可以改进的地方和一些难点,比如说类的大小(即是K的大小)不好确定。
而对于此算法用matlab编程会更加方便,而且可以生成相应的仿真图形,是视觉图形运算的比较好的工具。、
对于此算法,自己用了C++编写了一个:
/*
视觉机器学习 第一讲
K-means k均值
*/
#include<iostream>
#include<vector>
#include<algorithm>
#include<ctime>
#include<cstdlib>
using namespace std;
class Solution
{
public:
//k-means++ 法产生centroid,即是优化初始聚类中心的函数
vector<vector<double>> Generate_centroid(vector<vector<double>>&X, int K)//分类总数
{
vector<vector<double>>result;
vector<vector<double>>temp;//中间替换量
int N = X.size();//样本总个数
srand((unsigned int)time(0));//新种子产生随机数,每次都不一样
// rand() % N //随机的一个数【0,N-1】
result.push_back(X[rand() % N]);//初始随机化
for (int i = 1; i < K; i++)
{
int index;
index = Return_maxindex(X, result);
result.push_back(X[index]);
}
return result;
}
//K-means 方法
void K_means(vector<vector<double>>&X, vector<vector<double>>&C,int itera)//itera最大迭代次数
{
for (int k = 0; k < itera; k++)
{
vector<int>s(C.size(), 0);
for (int i = 0; i < C.size(); i++)
{
for (int j = 0; j < X.size(); j++)
{
if (compare(X[j], C, i))
{
s[i]++;
X[j][0] = i;
}
}
}
//更新聚类中心C
for (int i = 0; i < C.size(); i++)
{
double temp1 = 0.0,temp2=0.0;
for (int j = 0; j < X.size(); j++)
{
if (X[j][0] == i)
{
temp1 += X[j][1];
temp2 += X[j][2];
}
}
C[i][0] = i;
C[i][1] = temp1 / s[i];
C[i][2] = temp2 / s[i];
}
}
}
bool compare(vector<double>&x,vector<vector<double>>&C,int i)
{
for (int k = 0; k < C.size(); k++)
{
if (k == i)
continue;
if (((x[1] - C[i][1])*(x[1] - C[i][1]) + (x[2] - C[i][2])*(x[2] - C[i][2]))>((x[1] - C[k][1])*(x[1] - C[k][1]) + (x[2] - C[k][2])*(x[2] - C[k][2])))
return false;
}
return true;
}
private:
int Return_maxindex(vector<vector<double>>&X, vector<vector<double>>&C)
{
int index1=0;
int K = C.size();
double temp = X[0][1] * X[0][1] + X[0][2] * X[0][2];
for (int i = 0; i < X.size(); i++)
{
if (value(X[i], C) >temp)
{
temp = value(X[i], C);
index1 = i;
}
}
return index1;
}
double value(vector<double>&x, vector<vector<double>>&C)
{
int K = C.size();
double result = 0.0;
for (int i = 0; i < K; i++)
result += (x[1] - C[i][1])*(x[1] - C[i][1]) + (x[2] - C[i][2])*(x[2] - C[i][2]);
return result;
}
};
int main()
{
Solution s1;
vector<vector<double>>X{ { -1, 0, 1.5 }, { -1, 0.2, 1.5 }, { -1, 0.4, 1.5 }, { -1, 0.6, 1.5 },
{ -1, 0, 1.6 }, { -1, 0.2, 1.6 }, { -1, 0.4, 1.6 }, { -1, 0.6, 1.6 },
{ -1, 0, 1.7}, { -1, 0.2, 1.7 }, { -1, 0.4, 1.7 }, { -1, 0.6, 1.7 },
{ -1, 0, 1.8 }, { -1, 0.2, 1.8 }, { -1, 0.4, 1.8 }, { -1, 0.6, 1.8 },
{ -1, 0.8, 0 }, { -1, 1, 0 }, { -1, 1.2, 0 }, { -1, 1.4, 0 },
{ -1, 0.8, 0.5 }, { -1, 1, 0.5 }, {-1, 1.2, 0.5 }, { -1, 1.4, 0.5 },
{ -1, 0.8, 1 }, { -1, 1, 1 }, { -1, 1.2, 1 }, { -1, 1.4, 1 },
{ -1, 0.8, 1.5 }, { -1, 1, 1.5 }, { -1, 1.2, 1.5 }, { -1, 1.4, 1.5 },
{ -1, 1.4, 1.5 }, { -1, 1.6, 1.5 }, { -1, 1.8, 1.5 }, { -1, 2, 1.5 },
{ -1, 1.4, 1.6 }, { -1, 1.6, 1.6 }, { -1, 1.8, 1.6 }, { -1, 2, 1.6 },
{ -1, 1.4, 1.7 }, { -1, 1.6, 1.7 }, { -1, 1.8, 1.7 }, { -1, 2, 1.7 },
{ -1, 1.4, 1.8 }, { -1, 1.6, 1.8 }, { -1, 1.8, 1.8 }, { -1, 2, 1.8 }
};
vector<vector<double>>centorid;
centorid = s1.Generate_centroid(X, 3);
int itera;
cout << "输入迭代次数itera:";
cin >> itera;
s1.K_means(X, centorid, itera);
cout << "输出分类中心:" << endl;
for (int i = 0; i < centorid.size(); i++)
{
for (int j = 0; j < centorid[0].size(); j++)
{
cout << centorid[i][j] << ",";
}
cout << endl;
}
cout << "输出分类结果X:" << endl;
for (int i = 0; i < X.size(); i++)
{
for (int j = 0; j < X[0].size(); j++)
{
cout << X[i][j] << ",";
}
cout << endl;
}
system("pause");
return 0;
}