K-Means算法带界面程序演示
2015-12-18 21:05
267 查看
K-Means算法步骤
因为要做可视化界面,所以我们现在只讨论二维的情况,即每个元素用2个数表示。假如我们的元素集合是平面上的N个点,计算相似度用的是两点之间的欧氏距离(当然也可以使用其他距离公式,相关距离公式见下部分),两点距离越短则表示相似度越高。那么算法步骤大概是这个样子:
Step 1. 随机产生K个点,作为K个簇的中心(注意K<=N)
Step 2. 对N个点中的每一个点,计算该点离哪个中心最近,离哪个中心最近就属于哪个簇。
Step 3. 更新每个簇的中心(取簇中的元素的坐标的均值)
Step 4. 重复Step2和Step3直到所有簇的中心不再改变。
Java实现代码(带图形界面)
import java.awt.*;import java.awt.event.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.Random;
import java.applet.*;
class PaintovalPane extends JPanel
{
/*K-Means*/
int K = 5; //K个中心
int N = 50; //N个点
int D = 2; //二维元素
Random rand = new Random();
4000
class Point
{
Point()
{
initial();
}
void initial()
{
/*初始化为[0,600)的随机点,簇编号为-1,无意义*/
for (int i = 0; i < D; ++i)
x[i] = rand.nextDouble()*600;
clusterNum = -1;
}
double x[] = new double[D]; //坐标
int clusterNum; //簇编号
};
Point p[]; //数据点
Point centroid[]; //中心点
Point oldCentroid[]; //上一次的中心点,用于确定中心点是否不再改变
Color colors[]; //表示不同簇的颜色值
/*欧式距离*/
double Euclidean(Point p1, Point p2)
{
double dis = 0;
for (int i = 0; i < D; ++i)
dis += (p1.x[i]-p2.x[i])*(p1.x[i]-p2.x[i]);
return Math.sqrt(dis);
}
/*更新中心点*/
void updateCentroid(int clusterNum)
{
for (int i = 0; i < D; ++i)
centroid[clusterNum].x[i] = 0;
int clusterSize = 0;
for (int i = 0; i < N; ++i)
if (p[i].clusterNum == clusterNum)
{
clusterSize++;
for (int j = 0; j < D; ++j)
centroid[clusterNum].x[j] += p[i].x[j];
}
if (clusterSize == 0)
return;
for (int i = 0; i < D; ++i)
centroid[clusterNum].x[i] /= (double)clusterSize;
}
/*更新中心点的接口函数*/
void updateCentroids()
{
for (int i = 0; i < K; ++i)
updateCentroid(i);
}
/*分配数据点到哪个簇*/
void assignPoint(int x)
{
double minDis = 99999999;
int minIndex = 1;
for (int i = 0; i < K; ++i)
{
double curDis = Euclidean(p[x], centroid[i]);
if (curDis < minDis)
{
minDis = curDis;
minIndex = i;
}
}
p[x].clusterNum = minIndex;
}
/*分配数据点到哪个簇的接口函数*/
void assign()
{
for (int i = 0; i < N; ++i)
assignPoint(i);
}
/*判断2点是否同一个点*/
Boolean samePoint(Point p1, Point p2)
{
if (p1.clusterNum != p2.clusterNum)
return false;
for (int i = 0; i < D; ++i)
if (p1.x[i] != p2.x[i])
return false;
return true;
}
/*判断算法是否终止*/
Boolean stop()
{
/*如果每一个中心点都与上一次的中心点相同,则算法终止,否则更新oldCentroid*/
for (int i = 0; i < K; ++i)
if (!samePoint(oldCentroid[i], centroid[i]))
{
for (int j = 0; j < K; ++j)
copy(oldCentroid[j],centroid[j]);
return false;
}
return true;
}
/*令p1 = p2*/
void copy(Point p1, Point p2)
{
p1.clusterNum = p2.clusterNum;
for (int i = 0; i < D; ++i)
p1.x[i] = p2.x[i];
}
/*初始化*/
void init()
{
/*分配内存*/
p = new Point
;
centroid = new Point[K];
oldCentroid = new Point[K];
colors = new Color[K];
for (int i = 0; i < N; ++i)
{
p[i] = new Point();
p[i].initial();
}
for (int i = 0; i < K; ++i)
{
centroid[i] = new Point();
oldCentroid[i] = new Point();
centroid[i].initial();
oldCentroid[i].initial();
copy(oldCentroid[i],centroid[i]);
colors[i] = new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
}
}
/*默认构造函数,调用初始化函数*/
PaintovalPane()
{
init();
}
/*重载绘图函数*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.white);
/*画数据点(圆形),根据簇编号来确定颜色*/
for (int i = 0; i < N; ++i)
{
int x = (int)p[i].x[0], y = (int)p[i].x[1];
if (p[i].clusterNum == -1)
g.setColor(Color.black);
else
g.setColor(colors[p[i].clusterNum]);
g.fillOval(x, y, 15, 15);
}
/*画中心点(矩形),根据簇编号来确定颜色*/
for (int i = 0; i < K; ++i)
{
int x = (int)centroid[i].x[0], y = (int)centroid[i].x[1];
g.setColor(colors[i]);
g.fillRect(x, y, 15, 15);
}
}
}
class Drawing extends JFrame
{
/*声明一系列组件*/
JButton jButton1 = new JButton("Start");
JButton jButton2 = new JButton("Step");
JButton jButton3 = new JButton("Run");
JLabel label1 = new JLabel("Points");
JLabel label2 = new JLabel("Clusters");
JTextField textField1 = new JTextField("This is buffer for text", 15);
JTextField textField2 = new JTextField("This is buffer for text", 15);
JPanel jPanel = new JPanel();
PaintovalPane paint = new PaintovalPane();
Drawing()
{
setTitle("K-Means");
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize (660,710);
textField1.setText(String.valueOf(paint.N));
textField2.setText(String.valueOf(paint.K));
/*Start按钮的监听器*/
jButton1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
int input1 = Integer.parseInt(textField1.getText());
int input2 = Integer.parseInt(textField2.getText());
/*判断输入是否合法*/
if (input1 > 500 || input1 <= 0)
{
JOptionPane.showMessageDialog(null, "Please input the number between 1-500");
}
else if (input2 > input1 || input2 <= 0)
{
JOptionPane.showMessageDialog(null, "Please input the number between 1-Points");
}
else
{
paint.N = input1;
paint.K = input2;
paint.init();
paint.repaint();
jButton2.setText("Step");
jButton2.setEnabled(true);
jButton3.setText("Run");
jButton3.setEnabled(true);
}
}
});
/*Step按钮的监听器*/
jButton2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
paint.assign();
paint.updateCentroids();
/*算法终止的话让按钮变灰并提示算法结束*/
if (paint.stop())
{
jButton2.setText("End");
jButton2.setEnabled(false);
jButton3.setText("End");
jButton3.setEnabled(false);
}
paint.repaint();
}
});
/*Run按钮的监听器*/
jButton3.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
do
{
paint.assign();
paint.updateCentroids();
paint.repaint();
}
while(!paint.stop());
/*算法终止的话让按钮变灰并提示算法结束*/
jButton2.setText("End");
jButton2.setEnabled(false);
jButton3.setText("End");
jButton3.setEnabled(false);
}
});
jPanel.add(label1);
jPanel.add(textField1);
jPanel.add(label2);
jPanel.add(textField2);
jPanel.add(jButton1);
jPanel.add(jButton2);
jPanel.add(jButton3);
jPanel.setBackground(new Color(1,255,1));
add(BorderLayout.NORTH,jPanel);
add(BorderLayout.CENTER, paint);
}
}
public class Hello extends Applet
{
public static void main(String args[])
{
Drawing d = new Drawing();
}
}
程序效果
按下Start按下Step
按下Run
程序效果
按下Start按下Step
按下Run
文章转自于:http://www.cnblogs.com/chenyg32/
相关文章推荐
- 字节对齐小谈
- Assets目录下的特殊文件夹名称
- 链表
- AndroidAnnotations在Eclipse中配置
- mybaties报错:查询数据时,没有给无参构造报错
- 使用 Vagrant 打造跨平台开发环境
- MySQL 5.7.10最新版本源代码安装详细过程
- DFT做频谱分析再理解
- 本人第一个android游戏《新连连看》上架
- Nodejs解决2分钟限制
- EXCEL中常用的函数
- DateTime操作,时间范围,加减
- [NOIP2005]采药 T3
- 2种平台使用数据库异同
- 18 数据库
- 隐式intent
- leetcode刷题日记——Remove Linked List Elements
- 18 初级数据持久化
- [重装系统系列]fcitx 小企鹅输入法 安装 in ubuntu 15.04
- UVa 1590 IP Networks (IP网络)