winform的界面搭建比较简单,首先在界面上的左边产生两堆特征值为 0-100的二维样本。通过 c均值聚类及DBSCAN聚类将聚类结果显示在右边。样本点有x和y值,用List
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Text;
namespace PatternRecon
{
public partial class Form1 : Form
{
public List Cluster1=new List();
public List Cluster2=new List();
public List afterCluster1 = new List();
public List afterCluster2 = new List();
public Form1()
{
InitializeComponent();
InitCombo();
}
public void InitCombo()
{
this.comboBox1.Items.Add("c均值");
this.comboBox1.Items.Add("DBSCAN");
//设置默认值
this.textBox1.Text = "1";
this.textBox2.Text = "12";
//设置背景
afterCluster1.Clear();
afterCluster2.Clear();
this.pictureBox1.Image = (DrawCluster(afterCluster1, afterCluster2, false));
this.pictureBox2.Image = (DrawCluster(afterCluster1, afterCluster2, false));
}
//产生随机数种子
public static int GetRandomSeed()
{
byte[] bytes = new byte[4];
System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
}
//产生标准正太分布
public static double[] NormalDistribution()
{
Random rand = new Random(GetRandomSeed());
double[] y;
double u1, u2, v1=0, v2=0, s = 0, z1=0, z2=0;
while (s > 1 || s == 0)
{
u1 = rand.NextDouble();
u2 = rand.NextDouble();
v1 = 2 * u1 - 1;
v2 = 2 * u2 - 1;
s = v1 * v1 + v2 * v2;
}
z1 = Math.Sqrt(-2 * Math.Log(s) / s) * v1;
z2 = Math.Sqrt(-2 * Math.Log(s) / s) * v2;
y = new double[] { z1, z2 };
return y; //返回两个服从正态分布N(0,1)的随机数z0 和 z1
}
//确定
private void button1_Click(object sender, EventArgs e)
{
if (this.comboBox1.Text == "c均值")
{
//调用c均值
Caverage();
this.pictureBox2.Image = (DrawCluster(afterCluster1, afterCluster2,false));
}
else if (this.comboBox1.Text == "DBSCAN")
{
//调用DBSCAN
if (this.textBox1.Text == "" || this.textBox2.Text == "")
{
MessageBox.Show("请输入DBSCAN值");
}
else
{
DBSCAN();
this.pictureBox2.Image = (DrawCluster(afterCluster1, afterCluster2, false));
}
}
else
{
MessageBox.Show("请选择聚类方法!");
}
}
//绘图
public Bitmap DrawCluster(List m1,List m2,bool flag)
{
Bitmap bmp = new Bitmap(405, 405);
Graphics g = Graphics.FromImage(bmp);
Pen p = new Pen(Color.Black, 2);
Pen linep = new Pen(Color.FromArgb(30, Color.Black), 2);
Pen pm1;
Pen pm2;
if (flag==true)
{
pm1 = new Pen(Color.Red, 2);
pm2 = new Pen(Color.Green, 2);
}
else
{
pm1 = new Pen(Color.Brown, 2);
pm2 = new Pen(Color.Blue, 2);
}
Point p1 = new Point(400, 0);
Point p2 = new Point(400, 400);
Point p3 = new Point(0, 400);
Point p4 = new Point(400, 400);
try
{
//画线
g.Clear(Color.White);
g.DrawLine(p, p1, p2);
g.DrawLine(p, p3, p4);
g.DrawLine(p,new Point(0,0), p1);
g.DrawLine(p, new Point(0, 0), p3);
g.DrawString("高斯分布随机产生100个样品,特征值取值为0-10", new Font("宋体", 10), new SolidBrush(Color.Black), new PointF(10, 10));
for (int i = 1; i <= 9; i++)
{
g.DrawLine(linep, new Point(i * 40, 400), new Point(i * 40, 0));
g.DrawLine(linep, new Point(400, i * 40), new Point(0, i * 40));
g.DrawString(i.ToString(), new Font("宋体", 10), new SolidBrush(Color.Blue), new PointF(i * 40, 400 - 15));
g.DrawString(i.ToString(), new Font("宋体", 10), new SolidBrush(Color.Blue), new PointF(400 - 15, i * 40));
}
//画点
foreach(Point m1Point in m1)
{
g.DrawEllipse(pm1, m1Point.X, m1Point.Y, 2, 2);
}
foreach (Point m1Point in m2)
{
g.DrawEllipse(pm2, m1Point.X, m1Point.Y, 2, 2);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
g.Dispose();
p.Dispose();
pm1.Dispose();
pm2.Dispose();
linep.Dispose();
}
return bmp;
//描点
}
//用于产生两个均值
public int count = 0;
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
count++;
// MessageBox.Show(count.ToString());
if (count==1)
{
for (int i = 0; i < 50;i++ )
{
double[] point = NormalDistribution();
double x = point[0] +e.X/40;
double y = point[1] +e.Y/40;
int x1 = (int)(x * 40);
int x2 = (int)(y * 40);
Cluster1.Add(new Point(x1,x2));
}
}
if (count == 2)
{
for (int i = 0; i < 50; i++)
{
double[] point = NormalDistribution();
double x = point[0] + e.X / 40;
double y = point[1] + e.Y / 40;
int x1 = (int)(x * 40);
int x2 = (int)(y * 40);
Cluster2.Add(new Point(x1, x2));
}
this.pictureBox1.Image=(DrawCluster(Cluster1,Cluster2,true));
}
}
//c均值,按照PPT上的步骤写的
public void Caverage()
{
this.afterCluster1.Clear();
this.afterCluster2.Clear();
//初始化聚类中心
List Cluster=new List();
foreach(Point m1Point in Cluster1)
{
Cluster.Add(m1Point);
}
foreach(Point m2Point in Cluster2)
{
Cluster.Add(m2Point);
}
Point C1=Cluster[0];
Point C2=Cluster[1];
bool flag= true;
//判断聚类中心是否相等
while (flag)
{
// MessageBox.Show("聚类中心1:" + C1.X.ToString() + " " + C1.Y.ToString() + "聚类中心2:" + C2.X.ToString() + " " + C2.Y.ToString());
int N1 = 0;
int N2 = 0;
int C1x = 0;
int C2x = 0;
int C1y = 0;
int C2y = 0;
foreach (Point point in Cluster)
{
int s1 = Math.Abs(point.X - C1.X) + Math.Abs(point.Y - C1.Y);
int s2 = Math.Abs(point.X - C2.X) + Math.Abs(point.Y - C2.Y);
if(s1 Cluster = new List();
List temp1 = new List();
List temp2 = new List();
foreach (Point m1Point in Cluster1)
{
Cluster.Add(m1Point);
}
foreach (Point m2Point in Cluster2)
{
Cluster.Add(m2Point);
}
Point C1;
Point C2;
bool isC1Get = false;
bool isC2Get = false;
foreach (Point mm in Cluster)
{
if (isC1Get == false)
{
int count = 0;//记数
temp1.Clear();
foreach (Point mm1 in Cluster)
{
double banjing = Math.Sqrt(Math.Pow(mm1.X - mm.X, pow) + Math.Pow(mm1.Y - mm.Y, pow));
if (banjing < radius)
{
count++;
temp1.Add(mm1);
}
}
if (count >= MinPts)
{
C1 = mm;
isC1Get = true;
foreach (Point mm2 in temp1)
{
foreach (Point mm3 in Cluster)
{
double banjing = Math.Sqrt(Math.Pow(mm3.X - mm2.X, pow) + Math.Pow(mm3.Y - mm2.Y, pow));
if (banjing < radius && (afterCluster1.Contains(mm3) == false))
{
afterCluster1.Add(mm3);
}
}
}
}
}
else if (isC2Get == false)
{
if (afterCluster1.Contains(mm) == false)
{
int count = 0;//记数
temp2.Clear();
foreach (Point mm1 in Cluster)
{
double banjing = Math.Sqrt(Math.Pow(mm1.X - mm.X, pow) + Math.Pow(mm1.Y - mm.Y, pow));
if (banjing < radius)
{
count++;
temp2.Add(mm1);
}
}
if (count >= MinPts)
{
C2 = mm;
isC2Get = true;
foreach (Point mm2 in temp2)
{
foreach (Point mm3 in Cluster)
{
double banjing = Math.Sqrt(Math.Pow(mm3.X - mm2.X, pow) + Math.Pow(mm3.Y - mm2.Y, pow));
if (banjing < radius && (afterCluster1.Contains(mm3) == false) && afterCluster2.Contains(mm3) == false)
{
afterCluster2.Add(mm3);
}
}
}
}
}
else
{
continue;
}
}
else
{
break;
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//清除
private void button2_Click(object sender, EventArgs e)
{
this.Cluster1.Clear();
this.Cluster2.Clear();
this.afterCluster1.Clear();
this.afterCluster2.Clear();
count = 0;
Bitmap bmp = new Bitmap(405, 405);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.White);
g.Dispose();
this.pictureBox1.Image = (DrawCluster(afterCluster1, afterCluster2, false));
this.pictureBox2.Image = (DrawCluster(afterCluster1, afterCluster2, false));
}
//圈出不同,圈的之后注意比较一下中心
private void button3_Click(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)this.pictureBox2.Image;
Graphics g = Graphics.FromImage(bmp);
Pen p = new Pen(Color.Black,2);
int count1 = 0;
int count2 = 0;
List belongCluster1;
List belongCluster2;
foreach (Point m1Point in Cluster1)
{
if (afterCluster1.Contains(m1Point))
count1++;
if (afterCluster2.Contains(m1Point))
count2++;
}
if (count1 > count2)
{
belongCluster1 = afterCluster1;
belongCluster2 = afterCluster2;
}
else
{
belongCluster1 = afterCluster2;
belongCluster2 = afterCluster1;
}
//画出不同的地方
foreach (Point m1Point in Cluster1)
{
if (belongCluster1.Contains(m1Point) == false)
{
g.DrawEllipse(p, m1Point.X, m1Point.Y, 6, 6);
}
}
foreach (Point m1Point in Cluster2)
{
if (belongCluster2.Contains(m1Point) == false)
{
g.DrawRectangle(p, m1Point.X, m1Point.Y, 6, 6);
}
}
g.Dispose();
p.Dispose();
this.pictureBox2.Image = bmp;
}
}
}
最终的聚类结果:
demo下载:https://download.csdn.net/download/cc_fys/10770325
github demo下载:https://github.com/ccessl/cluster