1.K-means算法步骤
- 从数据中选择k个对象作为初始聚类中心;
- 计算每个聚类对象到聚类中心的距离来划分(被划分到距离最近的那个中心点的簇里);
- 再次计算每个聚类中心
- 重新开始步骤2和步骤3,进行迭代直到满足结束条件(当前迭代次数达到指定迭代次数、中心点坐标距离变化量低于指定值、每个簇里的元素或者元素数量不再发生变化等,根据不同要求确定不同结束条件)
- 确定最优的聚类中心
2.相关问题
1.计算距离
K-means算法采用的是欧氏距离:各维度差的平方和。
D
i
s
t
(
X
,
Y
)
=
∑
i
=
1
n
(
x
i
−
y
i
)
2
Dist(X,Y)=\sqrt{\sum_{i=1}^{n}(x_{i}-y_{i})^{2}}
Dist(X,Y)=i=1∑n(xi−yi)2
2. 如何计算中心点坐标
计算的公式和重心坐标公式是一致的,所有点每个维度的均值
c
e
n
t
e
r
(
∑
i
=
1
n
P
1
i
n
,
∑
i
=
1
n
P
2
i
n
,
.
.
.
,
∑
i
=
1
n
P
m
i
n
)
center(\frac{\sum_{i=1}^{n}P1_{i}}{n},\frac{\sum_{i=1}^{n}P2_{i}}{n},...,\frac{\sum_{i=1}^{n}Pm_{i}}{n})
center(n∑i=1nP1i,n∑i=1nP2i,...,n∑i=1nPmi)
具体代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define endl '\n'
struct Point {//存储点
vector<double> pos;//存储各维度值
int aff=-1;//所属中心点下标
} p[100];
int n,m,k,temp;//n:数据点数,m:点的维度,k:中心点数
vector<Point> center;//中心点坐标
double getdis(const Point &p1,const Point &p2) {//获取两点距离
double result=0;
for(int i=0; i<m; i++) {
result+=(p1.pos[i]-p2.pos[i])*(p1.pos[i]-p2.pos[i]);
}
return result;
}
void K_means() {
bool changed=true;
while(changed) {
changed=false;
for(int i=1; i<=n; i++) {//聚类
double mins=INT_MAX;
int t=0;
for(int j=0; j<center.size(); j++) {//遍历每一个中心点,找到离该点最近的那个中心点
if(getdis(p[i],center[j])<mins) {
t=j;
mins=getdis(p[i],center[j]);
}
}
if(p[i].aff!=t) {//如果该点的所属改变了,则说明要继续聚类
p[i].aff=t;
changed=true;
}
}
for(int t=0; t<k; t++) {//计算每一个簇的中心点,并更新中心点坐标
vector<double> pos(m,0);
int cnt=0;
for(int i=1; i<=n; i++) {
if(p[i].aff==t) {
cnt++;
for(int j=0; j<m; j++) {
pos[j]+=p[i].pos[j];
}
}
}
for(int j=0; j<m; j++) {
pos[j]/=cnt;
}
center[t].pos=pos;
}
}
}
void output(int index) {//输出各个簇内点
bool flag=false;
for(int i=1; i<=n; i++) {
if(p[i].aff==index) {
if(flag)cout<<",";
flag=true;
cout<<i;
}
}
cout<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
for(int i=1; i<=n; i++) {//输入数据点坐标
for(int j=0; j<m; j++) {
cin>>temp;
p[i].pos.push_back(temp);
}
}
for(int i=0; i<k; i++) {//输入中心点坐标
cin>>temp;
center.push_back(p[temp]);
}
K_means();//执行K_means算法
for(int i=0; i<k; i++) {//输出
cout<<"cluster"<<i+1<<":";
output(i);
}
return 0;
}