kmeans算法
1随机选取k个点作为中心点
2计算各点与所有中心点的距离
3每个点归入离它最近的那个中心点的划分
4计算每个划分的新中心点
5重新计算划分
6划分不再变化或满足停止条件时结束,否则重复45
代码
//用不确定的k开数组不能快速初始化
//2021.07.16 ECUST sxbkdpiang
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<iostream>
using namespace std;
const int DIMENSION=690; //690纬数据
const int NUM=320; //320组数据
float Data[NUM][DIMENSION]; //存放所有数据
void calculate(float Data[][DIMENSION],float kPoint[][DIMENSION],int k,int num);//递归计算
void readFile(FILE *fp,float Data[][DIMENSION]);//读入文件
int main()
{
//放在main里
srand((unsigned)time(NULL)); //随机数
FILE *fp;
readFile(fp,Data);
//读入k
int k;
cin>>k;
float kRandom[k][DIMENSION]; //一开始随机选择k个点
int Number[NUM]; //待选点
int Random[k]; //k个点分别是第几个点
//赋初值
for(int m=0;m<NUM;m++)
{
Number[m]=m;
}
for(int m=0;m<k;m++) //k个点不能重复
{
Random[m]=rand()%(NUM-m); //随机选点
for(int n=0;n<DIMENSION;n++)
{
kRandom[m][n]=Data[Random[m]][n]; //记录随机点
}
for(int n=Random[m];n<NUM-m-1;n++)
{
Number[n]=Number[n+1];
}
}
calculate(Data,kRandom,k,0);
fclose(fp);
return 0;
}
//读入文件
void readFile(FILE *fp,float Data[][DIMENSION])
{
float readf;
char readc;
if(!(fp=fopen("Data.txt","r")))
{
printf("error!");
}
for(int n=0;n<NUM;n++)
{
if(feof(fp))
{
break;
}
for(int m=0;m<DIMENSION;m++)
{
if(feof(fp))
{
break;
}
fscanf(fp,"%f",&Data[n][m]);
fgetc(fp);
}
}
}
void calculate(float Data[][DIMENSION] ,float kPoint[][DIMENSION],int k,int num)
{
/*
跑
新kPoint
比较一致,一致输出
不一致计数+1
迭代
*/
float kDistance[k][NUM];//每点和第k点的距离
//计算距离
for(int m=0;m<k;m++)
{
for(int n=0;n<NUM;n++)
{
float Distance=0;
for(int i=0;i<DIMENSION;i++)
{
Distance += ( Data[n][i] - kPoint[m][i] ) * ( Data[n][i] - kPoint[m][i] );
}
kDistance[m][n]=Distance/DIMENSION;
}
}
int Divide[NUM]={0}; //记录每个点的划分
int Count[k]={0}; //每个划分的计数
//计算每个点属于哪个划分
for(int m=0;m<NUM;m++)
{
int Low=0;//第几个划分
float Lowest=kDistance[0][m];
for(int n=0;n<k;n++)
{
if(kDistance[n][m] < Lowest)
{
Lowest=kDistance[n][m];
Low=n;
}
}
Divide[m]=Low;
Count[Low]++;
}
float Low[k][DIMENSION];//每个划分对应维度的总值,用来计算均值
//初始化
for(int m=0;m<NUM;m++)
{
for(int n=0;n<DIMENSION;n++)
{
Sum[Divide[m]][n]=0;
}
}
//加总
for(int m=0;m<NUM;m++)
{
for(int n=0;n<DIMENSION;n++)
{
Sum[Divide[m]][n]+=Data[m][n];
}
}
float kMeans[k][DIMENSION];//记录每个划分的均值点
//计算每个划分的均值点
for(int m=0;m<k;m++)
{
for(int n=0;n<DIMENSION;n++)
{
kMeans[m][n]=Sum[m][n]/Count[m];
}
}
int Flag=0;
//比较两组点是否一致
for(int m=0;m<k;m++)
{
if(Flag == -1)
{
break;
}
for(int n=0;n<DIMENSION;n++)
{
if(kPoint[m][n] != kMeans[m][n])
{
Flag=-1;
break;
}
}
}
if(Flag == 0 || num >= 20)//一致或循环太多次,输出
{
for(int m=0;m<k;m++)
{
cout<<Count[m]<<endl;
}
return;
}
else
{
calculate(Data,kMeans,k,num+1);
}
}