K-means聚類分析-互動式GUI演示(Matlab)
阿新 • • 發佈:2018-12-19
K-means聚類分析-互動式GUI演示(Matlab)
學習K-means的時候總是想,這應該是一個很酷的演算法,那麼酷的演算法,就應該有比較酷的demo來演示它,於是我寫了這個程式就是為了能裝逼,哦不,可以更直觀的和K-means演算法進行互動。原創程式,希望大家可以喜歡,多多指教。
目錄
原理簡介
- K-means是無監督學習的聚類演算法,是機器學習中最重要的演算法之一,他的目的是通過機器學習自動探索一批未知的資料,並將其分類。
- 具體的演算法流程如下:
|
實現效果和功能展示
- 參考圖2,使用 Matlab 編寫 GUI 介面程式,完成對 K-means
edit
框,可以修改初始樣本點個數,“中心點”下拉框可以選擇投放中心點的方式(如圖3所示,若選擇“自定義”,則可以使用游標在axes
上自定義選擇任意位置任意個數中心點如,若選擇“隨機2點”,則隨機產生2箇中心點,“隨機3點”,“隨機4點”同理。),“迭代”進度條,可以拉動以實現迭代,右邊的文字框可以實時顯示迭代的次數,迭代過程中中心點的運動軌跡將被繪出(如圖5所示為隨機3箇中心點進行迭代分類,不同類用不同的顏色區分)。需要注意的是,該程式可以迴圈演示,無需退出,重新選擇中心點後將會重新初始化整個過程。
|
|
|
|
|
|
|
一點體會
內嵌式 Matlab 程式設計的時候,主函式裡面的變數都會被視為
global
,為所有子函式可見。在宣告回撥函式的時候,’callback’,{ @classify,gca}
,的意思是宣告該控制元件的回撥函式為classify
,同時傳入引數gca
,需要注意的是,在定義classify
函式的時候,預設是有兩個控制元件引數hObj
(當前控制元件控制代碼),和event
(當前控制元件事件結構體)的,傳入的引數必須放在這兩個引數後面,才能實現正常的引數傳遞,如function classify(hObj,event,ax)
,傳入的引數gca
會賦值給臨時變數ax。產生多維正態隨機變數的時候使用
mvnrnd
(Multivariate normal random numbers),語法為R = mvnrnd(MU,SIGMA)
,其中SIGMA
為協方差矩陣而不是方差,應該注意的是多維隨機變數(隨機向量)要表示其內部隨機變數的關係,使用的是協方差,而不是方差,當然,內部隨機變數的方差位於這個協方差矩陣的對角。- 若要在
axes
中繪點,需要加上點標誌,如‘*’或者’.’,才會在plot
中繪點,不然其預設為繪製線。
程式碼
KmeansMain.m
function KmeansMain
close all;clear;clc;
%隨機生成隨機數
mu = [0 0];
%協方差矩陣,對角為方差值0.3,0.35
var = [0.3 0; 0 0.35];
samNum = 200;
data = mvnrnd(mu, var, samNum);
a = figure;
plot(gca, data(:,1), data(:,2), '*', 'color', 'k');hold on;
classNum = [];%類數
iterNum = 0;%迭代次數
x = [];
centerPoint = [];
centerPointPathAarry = [];
h_plotCenterPoint = [];%中心點繪製handle
h_plotPath = [];%中心點路徑繪製handle
%centerPointPathAarry結構
%第1次迭代|中心點1(x,y)|中心點2(x,y)|中心點3(x,y)|中心點n(x,y)
%第2次迭代|中心點1(x,y)|中心點2(x,y)|中心點3(x,y)|中心點n(x,y)
h_slider = uicontrol(a,'Style', 'slider',...
'SliderStep',[0.02 0.02],...
'Min',0,'Max',50,'Value',0,...
'Position', [400 20 100 20],...
'Callback', {@classify,gca});
h_edit = uicontrol(a,'Style', 'edit',...
'String', '200',...
'Position', [80 20 40 20],...
'Callback', {@paintRandomPoint,gca});
uicontrol('Style', 'popup',...
'String', '自定義|隨機2點|隨機3點|隨機4點',...
'Position', [200 22 120 20],...
'Callback', {@SpsfPoit,gca});
h_t1 = uicontrol('Style','text','String','迭代', ...
'Position', [355 20 40 20]);
h_textClassNum = uicontrol('Style','text','String','中心點', ...
'Position', [140 20 55 20]);
uicontrol('Style','text','String','樣本點數:', ...
'Position', [25 20 50 20]);
h_textshow = uicontrol('Style','text','String','0','Position', [500 20 20 20]);
set(gca,'xtick',[],'ytick',[],...
'title',text('string','Kmeans演示指令碼','color','k'));
xlim([-1.5 1.5]);ylim([-1.5 1.5]);
%%%%%%%%%%%%%%%%%%%%
function SpsfPoit(hObj,event,ax)
set(h_slider,'value',0); %清零滑動條,以實現從0迭代
cla;%清空axes
set(h_textshow,'string',0);%介面顯示的迭代次數清零
%控制代碼賦值為空
h_plotCenterPoint = [];
h_plotPath = [];
centerPointPathAarry = [];%軌跡歸零
plot(gca, data(:,1), data(:,2), '*', 'color', 'k');%樣本點顏色初始化
val = get(hObj, 'Value');%獲得popup menu的值
if val == 1
%選擇任意若干點作為中心點
[x, y] = ginput;
centerPoint = [x y];
[classNum, ~] = size(centerPoint);
repaintBeginPoint(h_plotCenterPoint, classNum, centerPoint);
elseif val == 2
%選擇任意2點作為中心點
centerPoint = rand(2, 2)*2-0.5;
[classNum, ~] = size(centerPoint);
repaintBeginPoint(h_plotCenterPoint, classNum, centerPoint);
elseif val == 3
%選擇任意3點作為中心點
centerPoint = rand(3, 2)*2-0.5;
[classNum, ~] = size(centerPoint);
repaintBeginPoint(h_plotCenterPoint, classNum, centerPoint);
elseif val == 4
%選擇任意4點作為中心點
centerPoint = rand(4,2)*2-0.5;
[classNum,~] = size(centerPoint);
repaintBeginPoint(h_plotCenterPoint, classNum, centerPoint);
end
[labelSample] = classifyAndShowAndLabel(classNum, centerPoint, data, samNum, gca);
centerPointPathAarry = [centerPointPathAarry; reshape(centerPoint', 1, classNum*2)];
set(h_textClassNum, 'string', [num2str(classNum) '箇中心點']);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%迭代分類函式%%%%%%%%%%%%%%%%%%%%
function classify(hObj,event,ax)
iterNum = round(get(hObj, 'value'));
set(h_textshow, 'string', iterNum);
%根據起始點分類,並且為不同的類標記不同顏色,返回帶標籤樣本資料
[labelSample] = classifyAndShowAndLabel(classNum, centerPoint, data, samNum, gca);
%重新獲得起始點矩陣centerPoint(x|y)
[centerPoint] = recalClassCenter(labelSample, classNum);
centerPointPathAarry = [centerPointPathAarry; reshape(centerPoint', 1, classNum*2)];
%重新繪製起始點centerPoint(x|y)到axes上
repaintBeginPoint(h_plotCenterPoint, classNum, centerPoint);
disp('path:');
disp(centerPointPathAarry);%將中心點的軌跡顯示出來
for i = 1:classNum
[selected_color] = colorMap(i, classNum);
h_plotPath(i)=plot(centerPointPathAarry(:, (i*2)-1), centerPointPathAarry(:,i*2), 'color', selected_color);
end
end
%%%%%%%%%%%%%%%函式部分%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%重新繪製起始點函式%%%%%%%%%
function repaintBeginPoint(handle_plo,classnum,R)
delete(h_plotCenterPoint);%清除繪製的中心點,並將控制代碼賦值為空
h_plotCenterPoint=[];
%重新繪製起始點,每個起始點的顏色不同
for i = 1:classnum
[selected_color] = colorMap(i, classnum);
h_plotCenterPoint(i) = plot(R(i,1), R(i,2), 'o', 'MarkerSize', 7, 'MarkerFaceColor', selected_color);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%重新計算類重心%%%%%%%%%%%%%%%%%%%%%%
function [newCenterPoint]=recalClassCenter(labelSample,classNum)
%R為重新被計算的類中心
newCenterPoint=[];
%分類並且計算每個類的重心
for i=1:classNum
%取出所有標籤為i類的所有行,即第i類的所有點
classs=labelSample(labelSample(:,3)==i,:);
%有用的只有第一列和第二列,去除標籤列
classs=[classs(:,1),classs(:,2)];
%重新計算重心
classs_repoint=mean(classs);
newCenterPoint=[newCenterPoint;classs_repoint];
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%根據起始點分類,並且為不同的類標記不同顏色,返回帶標籤樣本資料%%%%%%%%%
function [labelSample]=classifyAndShowAndLabel(classNum,centerPoint,data1,samNum,gca)
disArray=[];
for i=1:classNum
calproA=[centerPoint(i,:);data1(:,1),data1(:,2)];
Adist=pdist(calproA,'euclidean');
Adist=Adist(1:samNum)';
disArray=[disArray,Adist];
end
%拼接,得到距離矩陣,一列代表一個點到所有樣本點的距離
%disArray=[Adist Bdist];
%disp(disArray);
%獲取每一行最小值所在距離矩陣的列
%並和原樣本矩陣拼接為labelSample
%labelSample 表示被標記的原始樣本,每一行為一個樣本
%每一行的最後一列為標記值,在這裡標記是距離哪個樣本點最近。
minn=min(disArray');
cols=[];
for i=1:length(minn)
[row,col] = find(disArray==minn(i));
cols(i)=col;
end
cols=cols';
labelSample=[data1(:,1),data1(:,2),cols];
%將不同類的點標上不同的顏色
for i=1:samNum
[selected_color]=colorMap(labelSample(i,3),classNum);
plot(gca,data1(i,1),data1(i,2),'*','color',selected_color);
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%樣本點選擇並繪製函式%%%%%%%%%%%%%%%%%%%%%%%%%%%
function paintRandomPoint(hObj,event,ax)
textt = get(hObj, 'string');
samNum = str2num(textt);
data = mvnrnd(mu, var, samNum);
cla;
set(h_slider,'value',0); %清零滑動條,以實現從0迭代
plot(ax,data(:,1), data(:,2), '*', 'color', 'k');hold on;
end
end
colorMap.m
function [selected_color] = colorMap(num, max_color_value)
%顏色對映函式,輸入一個數值範圍0-max_clor_value,將
%顏色空間對映到0-max_clor_value的數值中去,輸入一個
% 這個範圍裡面的數num,可以返回一個顏色值selected_color
% jet_color = colormap(hsv(max_color_value));
% jet_color = colormap(cool(max_color_value));
% jet_color = colormap(hot(max_color_value));
% jet_color = colormap(pink(max_color_value));
% jet_color = colormap(gray(max_color_value));
% jet_color = colormap(pink(max_color_value));
% jet_color = colormap(bone(max_color_value));
jet_color = colormap(jet(max_color_value));
% jet_color = colormap(copper(max_color_value));
% jet_color = colormap(prim(max_color_value));
% jet_color = colormap(flag(max_color_value));
selected_color = jet_color(num,:);
可以複製上面的程式碼,或者可以到以下連結下載:https://download.csdn.net/download/qq_33826564/10574319
GitHub: https://github.com/swq123459/Kmeans-GUI