📄 clusterisodatadlg.cpp
字号:
// ClusterISODATADlg.cpp : implementation file
//
#include "stdafx.h"
#include "ClusterISODATA.h"
#include "ClusterISODATADlg.h"
#include <math.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
#define MAX 10
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CClusterISODATADlg dialog
CClusterISODATADlg::CClusterISODATADlg(CWnd* pParent /*=NULL*/)
: CDialog(CClusterISODATADlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CClusterISODATADlg)
m_centernum = 0;
m_equation = 0.0;
m_I = 0;
m_maxlength = 0.0;
m_maxvariance = 0.0;
m_minlength = 0.0;
m_minnum = 0;
m_minvariance = 0.0;
m_prenum = 0;
m_times = 0;
m_T = 0.0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CClusterISODATADlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CClusterISODATADlg)
DDX_Text(pDX, IDC_centernum, m_centernum);
DDX_Text(pDX, IDC_equation, m_equation);
DDX_Text(pDX, IDC_I, m_I);
DDX_Text(pDX, IDC_MaxLength, m_maxlength);
DDX_Text(pDX, IDC_MaxVariance, m_maxvariance);
DDX_Text(pDX, IDC_MinLength, m_minlength);
DDX_Text(pDX, IDC_minnum, m_minnum);
DDX_Text(pDX, IDC_MinVariance, m_minvariance);
DDX_Text(pDX, IDC_prenum, m_prenum);
DDX_Text(pDX, IDC_times, m_times);
DDX_Text(pDX, IDC_T, m_T);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CClusterISODATADlg, CDialog)
//{{AFX_MSG_MAP(CClusterISODATADlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_IN, OnButtonIn)
ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)
ON_BN_CLICKED(IDC_BUTTON_NEW, OnButtonNew)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CClusterISODATADlg message handlers
BOOL CClusterISODATADlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CClusterISODATADlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CClusterISODATADlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CClusterISODATADlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CClusterISODATADlg::OnButtonIn()
{
int i,j;
CFileDialog file(TRUE,"txt",".txt");
if(file.DoModal()==IDOK)
{
m_NewFileName=file.GetPathName();
}
if(m_NewFileName=="")
{
MessageBox("请先打开数据文本");
return;
}//异常处理,必须要打开数据
/* 这里的打开异常有问题,未打开会大量占用内存池 */
else
{
FILE *fp;
fp=fopen(m_NewFileName,"r");
fscanf(fp,"%d",&N);
for(i=0;i<N;i++)
{
fscanf(fp,"%lf",&featurex[i]);
fscanf(fp,"%lf",&featurey[i]);
}//获得文本数据
}
//初始化样本
m_pattern=new Pattern[N];
for(i=0;i<N;i++)
{
m_pattern[i].index=i+1;
m_pattern[i].feature[0]=featurex[i];
m_pattern[i].feature[1]=featurey[i];
}
UpdateData(true);
//计算样本距离作为归并系数的参考值
m_minlength=MAX;m_maxlength=0;
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
{
if(m_minlength>GetDistance(m_pattern[i],m_pattern[j]))
m_minlength=GetDistance(m_pattern[i],m_pattern[j]);
if(m_maxlength<GetDistance(m_pattern[i],m_pattern[j]))
m_maxlength=GetDistance(m_pattern[i],m_pattern[j]);
}
//求所有样本总方差作为标准差的参考值
double cen[2],equ[2];
for(i=0;i<2;i++)
{
cen[i]=0.0;
equ[i]=0.0;
}
for (i=0;i<N;i++)
{
cen[0]+=m_pattern[i].feature[0];
cen[1]+=m_pattern[i].feature[1];
}
for(i=0;i<2;i++)
cen[i]=cen[i]/(double)N;
for(i=0;i<N;i++)
{
equ[0]+=(m_pattern[i].feature[0]-cen[0])*(m_pattern[i].feature[0]-cen[0]);
equ[1]+=(m_pattern[i].feature[1]-cen[1])*(m_pattern[i].feature[1]-cen[1]);
}
for(i=0;i<2;i++)
{
equ[i]=sqrt(equ[i]/(double)N);
}
double minequ=MAX;
double maxequ=0.0;
for(i=0;i<2;i++)
{
if(m_minvariance>equ[i])
{
m_minvariance=equ[i];
}
if(m_maxvariance<equ[i])
{
m_maxvariance=equ[i];
}
}
UpdateData(false);
}
void CClusterISODATADlg::OnButtonOut()
{
// TODO: Add your control notification handler code here
if(m_NewFileName=="")
{
MessageBox("请先打开数据文本");
}//异常处理,必须要打开数据
UpdateData(true);
//输入参数
minnum=m_minnum;
T=m_T;
times=m_times;
equation=m_equation;
centernum=m_centernum;
l=m_l;
prenum=m_prenum;
//初始化类别
precenternum=prenum;
m_center=new Center[precenternum];
for(i=0;i<precenternum;i++)
{
m_center[i].index=i+1;
m_pattern[i].catagory=m_center[i].index;
m_center[i].feature[0]=m_pattern[i].feature[0];
m_center[i].feature[1]=m_pattern[i].feature[1];
}
int counter=1;//循环次数
while(counter<=times)
{//将所有样本归类
for(j=0;j<precenternum;j++)
{
m_center[j].patternnum=0;
}
for(i=0;i<N;i++)
{
double td=MAX;
int index=0;
for(j=0;j<precenternum;j++)
{
if(td>GetDistance(m_pattern[i],m_center[j]))
{
td=GetDistance(m_pattern[i],m_center[j]);
index=j;
}
}
m_center[index].patternnum++;
m_pattern[i].catagory=m_center[index].index;
}
//判断每类的样本是否足够
for(i=0;i<precenternum;i++)
{
if(m_center[i].patternnum<minnum)
{
for(j=i;j<precenternum-1;j++)
m_center[j]=m_center[j+1];
precenternum--;
}
}
//修正各中心
for(i=0;i<precenternum;i++)
{
CalCenter(&m_center[i]);
}
//计算所有样本到其相应聚类中心的距离的平均值
avedistance=new double[precenternum];
for(i=0;i<precenternum;i++)
{
avedistance[i]=0.0;//每一类中样本到聚类中心的距离平均值
}
allavedis=0.0;//全部样本的平均距离
for(i=0;i<precenternum;i++)
{
double dis=0.0;
int num=0;
for(j=0;j<N;j++)
{
if(m_pattern[j].catagory==m_center[i].index)
{
++num;
dis+=GetDistance(m_pattern[j],m_center[i]);
}
}
allavedis+=dis;
avedistance[i]=(double)(dis/(double)num);
}
allavedis/=N;
//合并
if((precenternum>=2*centernum)||((counter%2)==0)&&(precenternum>centernum/2)&&(precenternum<2*centernum))
{
//找距离最近的2个类
double td=MAX;
int ti,tj;
for(i=0;i<precenternum;i++)
for(j=i+1;j<precenternum;j++)
{
double tdin;
tdin=GetDistance(m_center[i],m_center[j]);
if(td<tdin)
{
td=tdin;
ti=i;
tj=j;
}
}
//判断是否进行合并
if(td<T)
{
//合并
for(i=0;i<precenternum;i++)
{
if(m_pattern[i].catagory==m_center[tj].index)
m_pattern[i].catagory=m_center[ti].index;
if(m_pattern[i].catagory>m_center[tj].index)
m_pattern[i].catagory--;
}
//形成新的类别
CalCenter(&m_center[ti]);
for(i=tj;i<precenternum-1;i++)
{
m_center[i]=m_center[i+1];
m_center[i].index--;
}
precenternum--;
}
}//合并完
else if((precenternum<=centernum/2)||((counter%2)!=0)&&(precenternum>centernum/2)&&(precenternum<2*centernum))//分裂
{//分裂
double **mequation;//标准差
int ti,tj;//记录最大标准差出现的位置,第ti+1号类的第tj+1位
mequation=new double *[precenternum];
for(i=0;i<precenternum;i++)
{
mequation[i]=new double[2];
mequation[i][0]=0.0;
mequation[i][1]=0.0;
}
//计算标准差向量
for(i=0;i<precenternum;i++)
{
for(j=0;j<N;j++)
{
if(m_pattern[j].catagory==m_center[i].index)
{
mequation[i][0]+=(m_pattern[j].feature[0]-m_center[i].feature[0])*(m_pattern[j].feature[0]-m_center[i].feature[0]);
mequation[i][1]+=(m_pattern[j].feature[1]-m_center[i].feature[1])*(m_pattern[j].feature[1]-m_center[i].feature[1]);
}
}
mequation[i][0]=sqrt(mequation[i][0]/m_center[i].patternnum);
mequation[i][1]=sqrt(mequation[i][1]/m_center[i].patternnum);
}
//找最大标准差
ti=0;
tj=0;
for(i=0;i<precenternum;i++)
for(j=0;j<2;j++)
{
if(mequation[i][j]>mequation[ti][tj])
{
ti=i;tj=j;
}
}
//判断是否要分裂
if(mequation[ti][tj]>equation)//大于给定阈值
{
if((avedistance[ti]>allavedis&&m_center[ti].patternnum)||(precenternum<=centernum/2))//类平均距离大于总平均距离
{
precenternum++;
Center *tempcenter;
tempcenter=new Center[precenternum];
for(i=0;i<precenternum-1;i++)
{
tempcenter[i]=m_center[i];
tempcenter[precenternum-1].index=precenternum;
}
for(j=0;j<2;j++)
{
tempcenter[precenternum-1].feature[j]=m_center[ti].feature[j];
}
tempcenter[precenternum-1].feature[tj]-=0.5*mequation[ti][tj];
tempcenter[ti].feature[tj]+=0.5*mequation[ti][tj];
tempcenter[ti].patternnum--;
m_center=tempcenter;
}
}
//修正各中心
for(i=0;i<precenternum;i++)
{
CalCenter(&m_center[i]);
}
}//end 分裂
counter++;
}//end while
UpdateData(false);
CString str="聚类分析结果.txt";//结果输出
FILE *fpt;
fpt=fopen(str,"w+");
for(j=0;j<N;j++)
{
for(i=0;i<precenternum;i++)
{
if(m_center[i].index==m_pattern[j].catagory)
{
fprintf(fpt,"%s%4.2f %4.2f%s%d%s%4.2f %4.2f%s\n","(",m_pattern[j].feature[0],m_pattern[j].feature[1],")属于第",m_center[i].index,"类(",m_center[i].feature[0],m_center[i].feature[1],")");
}
}
}
fclose(fpt);
ShellExecute(hwnd,NULL,str,NULL,NULL,SW_SHOWNORMAL);
}
double CClusterISODATADlg::GetDistance(CClusterISODATADlg::Center mCenter1,CClusterISODATADlg::Center mCenter2)
{
double result;
result=(mCenter1.feature[0]-mCenter2.feature[0])*(mCenter1.feature[0]-mCenter2.feature[0])+(mCenter1.feature[1]-mCenter2.feature[1])*(mCenter1.feature[1]-mCenter2.feature[1]);
return (double)sqrt(result);
}
double CClusterISODATADlg::GetDistance(CClusterISODATADlg::Pattern pattern,CClusterISODATADlg::Center center)
{
double result;
result=(pattern.feature[0]-center.feature[0])*(pattern.feature[0]-center.feature[0])+(pattern.feature[1]-center.feature[1])*(pattern.feature[1]-center.feature[1]);
return (double)sqrt(result);
}
double CClusterISODATADlg::GetDistance(CClusterISODATADlg::Pattern pattern1,CClusterISODATADlg::Pattern pattern2)
{
double result;
result=(pattern1.feature[0]-pattern2.feature[0])*(pattern1.feature[0]-pattern2.feature[0])+(pattern1.feature[1]-pattern2.feature[1])*(pattern1.feature[1]-pattern2.feature[1]);
return (double)sqrt(result);
}
void CClusterISODATADlg::CalCenter(CClusterISODATADlg::Center *pcenter)
{
int i;
double x=0.0,y=0.0;
for(i=0;i<N;i++)
{
if(m_pattern[i].catagory==pcenter->index)
{
x+=m_pattern[i].feature[0];
y+=m_pattern[i].feature[1];
}
}
if(x==0.0&&y==0.0)
{
return;
}
pcenter->feature[0]=x/double(pcenter->patternnum);
pcenter->feature[1]=y/double(pcenter->patternnum);
}
void CClusterISODATADlg::OnButtonNew()
{
// TODO: Add your control notification handler code here
ShellExecute(NULL,"Open","C:/Windows/Notepad.exe",NULL,NULL,SW_SHOWNORMAL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -