大數(shù)據(jù)分析之聚類(lèi)算法
在防城港等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作按需網(wǎng)站設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站制作,成都全網(wǎng)營(yíng)銷(xiāo)推廣,成都外貿(mào)網(wǎng)站建設(shè),防城港網(wǎng)站建設(shè)費(fèi)用合理。
1. 什么是聚類(lèi)算法
所謂聚類(lèi),就是比如給定一些元素或者對(duì)象,分散存儲(chǔ)在數(shù)據(jù)庫(kù)中,然后根據(jù)我們感興趣的對(duì)象屬性,對(duì)其進(jìn)行聚集,同類(lèi)的對(duì)象之間相似度高,不同類(lèi)之間差異較大。最大特點(diǎn)就是事先不確定類(lèi)別。
這其中最經(jīng)典的算法就是KMeans算法,這是最常用的聚類(lèi)算法,主要思想是:在給定K值和K個(gè)初始類(lèi)簇中心點(diǎn)的情況下,把每個(gè)點(diǎn)(亦即數(shù)據(jù)記錄)分到離其最近的類(lèi)簇中心點(diǎn)所代表的類(lèi)簇中,所有點(diǎn)分配完畢之后,根據(jù)一個(gè)類(lèi)簇內(nèi)的所有點(diǎn)重新計(jì)算該類(lèi)簇的中心點(diǎn)(取平均值),然后再迭代的進(jìn)行分配點(diǎn)和更新類(lèi)簇中心點(diǎn)的步驟,直至類(lèi)簇中心點(diǎn)的變化很小,或者達(dá)到指定的迭代次數(shù)。
KMeans算法本身思想比較簡(jiǎn)單,但是合理的確定K值和K個(gè)初始類(lèi)簇中心點(diǎn)對(duì)于聚類(lèi)效果的好壞有很大的影響。
聚類(lèi)算法實(shí)現(xiàn)
假設(shè)對(duì)象集合為D,準(zhǔn)備劃分為k個(gè)簇。
基本算法步驟如下:
1、從D中隨機(jī)取k個(gè)元素,作為k個(gè)簇的各自的中心。
2、分別計(jì)算剩下的元素到k個(gè)簇中心的相異度,將這些元素分別劃歸到相異度最低的簇。
3、根據(jù)聚類(lèi)結(jié)果,重新計(jì)算k個(gè)簇各自的中心,計(jì)算方法是取簇中所有元素各自維度的算術(shù)平均數(shù)。
4、將D中全部元素按照新的中心重新聚類(lèi)。
5、重復(fù)第4步,直到聚類(lèi)結(jié)果不再變化。
6、將結(jié)果輸出。
核心Java代碼如下:
/**
* 迭代計(jì)算每個(gè)點(diǎn)到各個(gè)中心點(diǎn)的距離,選擇最小距離將該點(diǎn)劃入到合適的分組聚類(lèi)中,反復(fù)進(jìn)行,直到
* 分組不再變化或者各個(gè)中心點(diǎn)不再變化為止。
* @return
*/
public List[] comput() {
List[] results = new ArrayList[k];//為k個(gè)分組,分別定義一個(gè)聚簇集合,未來(lái)放入元素。
boolean centerchange = true;//該變量存儲(chǔ)中心點(diǎn)是否發(fā)生變化
while (centerchange) {
iterCount++;//存儲(chǔ)迭代次數(shù)
centerchange = false;
for (int i = 0; i k; i++) {
results[i] = new ArrayListT();
}
for (int i = 0; i players.size(); i++) {
T p = players.get(i);
double[] dists = new double[k];
for (int j = 0; j initPlayers.size(); j++) {
T initP = initPlayers.get(j);
/* 計(jì)算距離 這里采用的公式是兩個(gè)對(duì)象相關(guān)屬性的平方和,最后求開(kāi)方*/
double dist = distance(initP, p);
dists[j] = dist;
}
int dist_index = computOrder(dists);//計(jì)算該點(diǎn)到各個(gè)質(zhì)心的距離的最小值,獲得下標(biāo)
results[dist_index].add(p);//劃分到對(duì)應(yīng)的分組。
}
/*
* 將點(diǎn)聚類(lèi)之后,重新尋找每個(gè)簇的新的中心點(diǎn),根據(jù)每個(gè)點(diǎn)的關(guān)注屬性的平均值確立新的質(zhì)心。
*/
for (int i = 0; i k; i++) {
T player_new = findNewCenter(results[i]);
System.out.println("第"+iterCount+"次迭代,中心點(diǎn)是:"+player_new.toString());
T player_old = initPlayers.get(i);
if (!IsPlayerEqual(player_new, player_old)) {
centerchange = true;
initPlayers.set(i, player_new);
}
}
}
return results;
}
上面代碼是其中核心代碼,我們根據(jù)對(duì)象集合List和提前設(shè)定的k個(gè)聚集,最終完成聚類(lèi)。我們測(cè)試一下,假設(shè)要測(cè)試根據(jù)NBA球員的場(chǎng)均得分情況,進(jìn)行得分高中低的聚集,很簡(jiǎn)單,高得分在一組,中等一組,低得分一組。
我們定義一個(gè)Player類(lèi),里面有屬性goal,并錄入數(shù)據(jù)。并設(shè)定分組數(shù)目為k=3。
測(cè)試代碼如下:
List listPlayers = new ArrayList();
Player p1 = new Player();
p1.setName(“mrchi1”);
p1.setGoal(1);
p1.setAssists(8);
listPlayers.add(p1);
Player p2 = new Player();
p2.setName("mrchi2");
p2.setGoal(2);
listPlayers.add(p2);
Player p3 = new Player();
p3.setName("mrchi3");
p3.setGoal(3);
listPlayers.add(p3);
//其他對(duì)象定義此處略。制造幾個(gè)球員的對(duì)象即可。
KmeansPlayer kmeans = new KmeansPlayer(listPlayers, 3);
ListPlayer[] results = kmeans.comput();
for (int i = 0; i results.length; i++) {
System.out.println("類(lèi)別" + (i + 1) + "聚集了以下球員:");
ListPlayer list = results[i];
for (Player p : list) {
System.out.println(p.getName() + "---" + p.getGoal()
}
}
算法運(yùn)行結(jié)果:
可以看出中心點(diǎn)經(jīng)歷了四次迭代變化,最終分類(lèi)結(jié)果也確實(shí)是相近得分的分到了一組。當(dāng)然這種算法有缺點(diǎn),首先就是初始的k個(gè)中心點(diǎn)的確定非常重要,結(jié)果也有差異。可以選擇彼此距離盡可能遠(yuǎn)的K個(gè)點(diǎn),也可以先對(duì)數(shù)據(jù)用層次聚類(lèi)算法進(jìn)行聚類(lèi),得到K個(gè)簇之后,從每個(gè)類(lèi)簇中選擇一個(gè)點(diǎn),該點(diǎn)可以是該類(lèi)簇的中心點(diǎn),或者是距離類(lèi)簇中心點(diǎn)最近的那個(gè)點(diǎn)。
幾種典型的聚類(lèi)融合算法:
1.基于超圖劃分的聚類(lèi)融合算法
(1)Cluster-based Similarity Partitioning Algorithm(GSPA)
(2)Hyper Graph-Partitioning Algorithm(HGPA)
(3)Meta-Clustering Algorithm(MCLA)
2.基于關(guān)聯(lián)矩陣的聚類(lèi)融合算法
Voting-K-Means算法。
3.基于投票策略的聚類(lèi)融合算法
w-vote是一種典型的基于加權(quán)投票的聚類(lèi)融合算法。
同時(shí)還有基于互信息的聚類(lèi)融合算法和基于有限混合模型的聚類(lèi)融合算法。
二、基于關(guān)聯(lián)矩陣的聚類(lèi)融合算法——Voting-K-Means算法
Voting-K-Means算法是一種基于關(guān)聯(lián)矩陣的聚類(lèi)融合算法,關(guān)聯(lián)矩陣的每一行和每一列代表一個(gè)數(shù)據(jù)點(diǎn),關(guān)聯(lián)矩陣的元素表示數(shù)據(jù)集中數(shù)據(jù)點(diǎn)對(duì)共同出現(xiàn)在同一個(gè)簇中的概率。
算法過(guò)程:
1.在一個(gè)數(shù)據(jù)集上得到若干個(gè)聚類(lèi)成員;
2.依次掃描這些聚類(lèi)成員,如果數(shù)據(jù)點(diǎn)i和j在某個(gè)聚類(lèi)成員中被劃分到同一個(gè)簇中,那么就在關(guān)聯(lián)矩陣對(duì)應(yīng)的位置計(jì)數(shù)加1;關(guān)聯(lián)矩陣中的元素值越大,說(shuō)明該元素對(duì)應(yīng)的兩個(gè)數(shù)據(jù)點(diǎn)被劃分到同一個(gè)簇中的概率越大;
3.得到關(guān)聯(lián)矩陣之后,Voting-K-Means算法依次檢查關(guān)聯(lián)矩陣中的每個(gè)元素,如果它的值大于算法預(yù)先設(shè)定的閥值,就把這個(gè)元素對(duì)應(yīng)的兩個(gè)數(shù)據(jù)點(diǎn)劃分到同一個(gè)簇中。
Voting-K-Means算法的優(yōu)缺點(diǎn):
Voting-K-Means算法不需要設(shè)置任何參數(shù),在聚類(lèi)融合的過(guò)程中可以自動(dòng)地的選擇簇的個(gè)數(shù) 并且可以處理任意形狀的簇。因?yàn)閂oting-K-Means算法在聚類(lèi)融合過(guò)程中是根據(jù)兩個(gè)數(shù)據(jù)點(diǎn)共同出現(xiàn)在同一個(gè)簇中的可能性大小對(duì)它們進(jìn)行劃分的,所以只要兩個(gè)數(shù)據(jù)點(diǎn)距離足夠近,它們就會(huì)被劃分到一個(gè)簇中。
Voting-K-Means算法的缺點(diǎn)是時(shí)間復(fù)雜度較高,它的時(shí)間復(fù)雜度是O(n^2);需要較多的聚類(lèi)成員,如果聚類(lèi)成員達(dá)不到一定規(guī)模,那么關(guān)聯(lián)矩陣就不能準(zhǔn)確反映出兩個(gè)數(shù)據(jù)點(diǎn)出現(xiàn)在同一個(gè)簇的概率。
package clustering;import java.io.FileWriter;import weka.clusterers.ClusterEvaluation;import weka.clusterers.SimpleKMeans;import weka.core.DistanceFunction;import weka.core.EuclideanDistance;import weka.core.Instances;import weka.core.converters.ConverterUtils.DataSource;import weka.filters.unsupervised.attribute.Remove;public class Votingkmeans2 extends SimpleKMeans { /** 生成的序列號(hào) */ private static final long serialVersionUID = 1557181390469997876L; /** 劃分的簇?cái)?shù) */ private int m_NumClusters; /** 每個(gè)劃分的簇中的實(shí)例的數(shù)量 */ public int[] m_ClusterSizes; /** 使用的距離函數(shù),這里是歐幾里德距離 */ protected DistanceFunction m_DistanceFunction = new EuclideanDistance(); /** 實(shí)例的簇號(hào)賦值 */ protected int[] m_Assignments; /** 設(shè)定聚類(lèi)成員融合閥值 */ private final static double THREASOD = 0.5; /** 生成一個(gè)聚類(lèi)器 */ public void buildClusterer(Instances data) throws Exception{ final int numinst = data.numInstances(); // 數(shù)據(jù)集的大小 double [][]association = new double[numinst][numinst]; // 定義并初始化一個(gè)關(guān)聯(lián)矩陣 int numIteration = 40; // 設(shè)置生成的聚類(lèi)成員數(shù) final int k = (int)Math.sqrt(numinst); // 設(shè)置K-Means聚類(lèi)算法參數(shù)——簇?cái)?shù) for(int i = 0; i numIteration; i++) { if(data.classIndex() == -1) data.setClassIndex(data.numAttributes() - 1); // 索引是從0開(kāi)始 String[] filteroption = new String[2]; filteroption[0] = "-R"; filteroption[1] = String.valueOf(data.classIndex() + 1);// 索引是從1開(kāi)始 Remove remove = new Remove(); remove.setOptions(filteroption); remove.setInputFormat(data); /* 使用過(guò)濾器模式生成新的數(shù)據(jù)集;新數(shù)據(jù)集是去掉類(lèi)標(biāo)簽之后的數(shù)據(jù)集 */ Instances newdata = weka.filters.Filter.useFilter(data, remove); /* 生成一個(gè)K-Means聚類(lèi)器 */ SimpleKMeans sm = new SimpleKMeans(); sm.setNumClusters(k); sm.setPreserveInstancesOrder(true); // 保持?jǐn)?shù)據(jù)集實(shí)例的原始順序 sm.setSeed(i); // 通過(guò)設(shè)置不同的種子,設(shè)置不同的簇初始中心點(diǎn),從而得到不同的聚類(lèi)結(jié)果 sm.buildClusterer(newdata); int[] assigm = sm.getAssignments(); // 得到數(shù)據(jù)集各個(gè)實(shí)例的賦值 /* 建立關(guān)聯(lián)矩陣 */ for(int j = 0; j numinst; j++) { for(int m = j; m numinst; m++) { if(assigm[j] == assigm[m]) { association[j][m] = association[j][m] + 1.0 / numIteration ; } } } } System.out.println(); /* 將生成的關(guān)聯(lián)矩陣寫(xiě)入.txt文件(注:生成的txt文本文件在e:/result.txt中) */ FileWriter fw = new FileWriter("e://result.txt"); for(int j = 0; j numinst; j++) { for(int m = j; m numinst; m++) { //由于關(guān)聯(lián)矩陣是對(duì)稱的,為了改進(jìn)算法的效率,只計(jì)算矩陣的上三角 String number = String.format("%8.2f", association[j][m]); fw.write(number); } fw.write("\n"); } /* 處理關(guān)聯(lián)矩陣,分別考慮了兩種情況 :1.關(guān)聯(lián)矩陣中某個(gè)元素對(duì)應(yīng)的兩個(gè)數(shù)據(jù)點(diǎn)已經(jīng)被劃分到了不同的簇中 * 2.兩個(gè)數(shù)據(jù)點(diǎn)中有一個(gè)或者兩個(gè)都沒(méi)有被劃分到某個(gè)簇中。 */ int[] flag = new int[numinst]; int[] flagk = new int[k]; int[] finallabel = new int[numinst]; for(int m = 0; m numinst; m++) { for(int n = m; n numinst; n++) { if(association[m][n] THREASOD) { if(flag[m] == 0 flag[n] == 0) { // 兩個(gè)數(shù)據(jù)點(diǎn)都沒(méi)有被劃分到某個(gè)簇中, int i = 0; // 將他們劃分到同一個(gè)簇中即可 while (i k flagk[i] == 1) i = i + 1; finallabel[m] = i; finallabel[n] = i; flag[m] = 1; flag[n] = 1; flagk[i] = 1; } else if (flag[m] == 0 flag[n] == 1) { // 兩個(gè)數(shù)據(jù)點(diǎn)中有一個(gè)沒(méi)有被劃分到某個(gè)簇中, finallabel[m] = finallabel[n]; // 將他們劃分到同一個(gè)簇中即可 flag[m] = 1; } else if (flag[m] == 1 flag[n] == 0) { finallabel[n] = finallabel[m]; flag[n] = 1; } else if (flag[m] == 1 flag[n] == 1 finallabel[m] != finallabel[n]) { // 兩個(gè)數(shù)據(jù)點(diǎn)已被劃分到了不同的簇中, flagk[finallabel[n]] = 0; // 將它們所在的簇合并 int temp = finallabel[n]; for(int i = 0; i numinst; i++) { if(finallabel[i] == temp) finallabel[i] = finallabel[m]; } } } } } m_Assignments = new int[numinst]; System.out.println("基于關(guān)聯(lián)矩陣的聚類(lèi)融合算法——Voting-K-Means算法的最終聚類(lèi)結(jié)果"); for(int i = 0; i numinst; i++) { m_Assignments[i] = finallabel[i]; System.out.print(finallabel[i] + " "); if((i+1) % 50 == 0) System.out.println(); } for(int i = 0; i k; i++) { if(flagk[i] == 1) m_NumClusters++; } } /** * return a string describing this clusterer * * @return a description of the clusterer as a string */ public String toString() { return "Voting-KMeans\n"; } public static void main(String []args) { try {String filename="e://weka-data//iris.arff"; Instances data = DataSource.read(filename); Votingkmeans2 vk = new Votingkmeans2(); vk.buildClusterer(data); /* 要生成Voting-K-Means的聚類(lèi)評(píng)估結(jié)果包括準(zhǔn)確率等需要覆蓋重寫(xiě)toString()方法; * 因?yàn)闆](méi)有覆蓋重寫(xiě),所以這里生產(chǎn)的評(píng)估結(jié)果沒(méi)有具體內(nèi)容。 */ ClusterEvaluation eval = new ClusterEvaluation(); eval.setClusterer(vk); eval.evaluateClusterer(new Instances(data)); System.out.println(eval.clusterResultsToString()); } catch (Exception e) { e.printStackTrace(); }}}
分析代碼時(shí)注意:得到的類(lèi)成員變量m_Assignments就是最終Voting-K-Means聚類(lèi)結(jié)果;由于是采用了開(kāi)源機(jī)器學(xué)習(xí)軟件Weka中實(shí)現(xiàn)的SimpleKMeans聚類(lèi)算法,初始時(shí)要指定簇的個(gè)數(shù),這里是數(shù)據(jù)集大小開(kāi)根號(hào)向下取整;指定的閥值為0.5,即當(dāng)關(guān)聯(lián)矩陣元素的值大于閥值時(shí),才對(duì)該元素對(duì)應(yīng)的兩個(gè)數(shù)據(jù)點(diǎn)進(jìn)行融合,劃分到一個(gè)簇中,考慮兩種情況,代碼注釋已有,這里不再詳述。但聚類(lèi)融合的實(shí)驗(yàn)結(jié)果并不理想,鶯尾花數(shù)據(jù)集irsi.arff是數(shù)據(jù)挖掘?qū)嶒?yàn)中最常用的數(shù)據(jù)集,原數(shù)據(jù)集共有三個(gè)類(lèi);但本實(shí)驗(yàn)進(jìn)行四十個(gè)聚類(lèi)成員的融合,其最終聚類(lèi)結(jié)果劃分成兩個(gè)簇;其原因可能有兩個(gè):一是算法本身的問(wèn)題,需要使用其他更加優(yōu)化的聚類(lèi)融合算法;二是實(shí)現(xiàn)上的問(wèn)題,主要就在聚類(lèi)結(jié)果的融合上,需要進(jìn)行一步對(duì)照關(guān)聯(lián)矩陣進(jìn)行邏輯上的分析,找出代碼中的問(wèn)題。關(guān)聯(lián)矩陣文本文件
---------------------
本文來(lái)自 Turingkk 的CSDN 博客 ,全文地址請(qǐng)點(diǎn)擊:
K-MEANS算法:
k-means 算法接受輸入量 k ;然后將n個(gè)數(shù)據(jù)對(duì)象劃分為 k個(gè)聚類(lèi)以便使得所獲得的聚類(lèi)滿足:同一聚類(lèi)中的對(duì)象相似度較高;而不同聚類(lèi)中的對(duì)象相似度較小。聚類(lèi)相似度是利用各聚類(lèi)中對(duì)象的均值所獲得一個(gè)“中心對(duì)象”(引力中心)來(lái)進(jìn)行計(jì)算的。
k-means 算法的工作過(guò)程說(shuō)明如下:首先從n個(gè)數(shù)據(jù)對(duì)象任意選擇 k 個(gè)對(duì)象作為初始聚類(lèi)中心;而對(duì)于所剩下其它對(duì)象,則根據(jù)它們與這些聚類(lèi)中心的相似度(距離),分別將它們分配給與其最相似的(聚類(lèi)中心所代表的)聚類(lèi);然后再計(jì)算每個(gè)所獲新聚類(lèi)的聚類(lèi)中心(該聚類(lèi)中所有對(duì)象的均值);不斷重復(fù)這一過(guò)程直到標(biāo)準(zhǔn)測(cè)度函數(shù)開(kāi)始收斂為止。一般都采用均方差作為標(biāo)準(zhǔn)測(cè)度函數(shù). k個(gè)聚類(lèi)具有以下特點(diǎn):各聚類(lèi)本身盡可能的緊湊,而各聚類(lèi)之間盡可能的分開(kāi)。
具體如下:
輸入:k, data[n];
(1) 選擇k個(gè)初始中心點(diǎn),例如c[0]=data[0],…c[k-1]=data[k-1];
(2) 對(duì)于data[0]….data[n], 分別與c[0]…c[n-1]比較,假定與c[i]差值最少,就標(biāo)記為i;
(3) 對(duì)于所有標(biāo)記為i點(diǎn),重新計(jì)算c[i]=/標(biāo)記為i的個(gè)數(shù);
(4) 重復(fù)(2)(3),直到所有c[i]值的變化小于給定閾值。
算法實(shí)現(xiàn)起來(lái)應(yīng)該很容易,就不幫你編寫(xiě)代碼了。
第一次迭代下,除了a4點(diǎn),其他點(diǎn)都?xì)w為一類(lèi)c1:(a1 a2 a3 a5);c2:(a4) 聚類(lèi)中心:c1:(2,2);c2(5,4)(聚類(lèi)中心的計(jì)算方式是平均類(lèi)中所有點(diǎn))
第二次迭代下,c1(a1 a2 a5);c2(a3 a4) 聚類(lèi)中心c1:(4/3,5/3);c2(9/2 7/2)
第三次迭代下,c1(a1 a2 a5);c2(a3 a4) 聚類(lèi)中心c1:(4/3,5/3);c2(9/2 7/2)結(jié)果已經(jīng)穩(wěn)定跳出循環(huán)
本文所有實(shí)現(xiàn)代碼均來(lái)自《Python機(jī)器學(xué)習(xí)及實(shí)戰(zhàn)》
#-*- coding:utf-8 -*-
#分別導(dǎo)入numpy、matplotlib、pandas,用于數(shù)學(xué)運(yùn)算、作圖以及數(shù)據(jù)分析
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#第一步:使用pandas讀取訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)
digits_train = pd.read_csv('',header=None)
digits_test = pd.read_csv('',header=None)
#第二步:已知原始數(shù)據(jù)有65個(gè)特征值,前64個(gè)是像素特征,最后一個(gè)是每個(gè)圖像樣本的數(shù)字類(lèi)別
#從訓(xùn)練集和測(cè)試集上都分離出64維度的像素特征和1維度的數(shù)字目標(biāo)
X_train = digits_train[np.arange(64)]
y_train = digits_train[64]
X_test = digits_test[np.arange(64)]
y_test = digits_test[64]
#第三步:使用KMeans模型進(jìn)行訓(xùn)練并預(yù)測(cè)
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=10)
kmeans.fit(X_train)
kmeans_y_predict = kmeans.predict(X_test)
#第四步:評(píng)估KMeans模型的性能
#如何評(píng)估聚類(lèi)算法的性能?
#1.Adjusted Rand Index(ARI) 適用于被用來(lái)評(píng)估的數(shù)據(jù)本身帶有正確類(lèi)別的信息,ARI指標(biāo)和計(jì)算Accuracy的方法類(lèi)似
#2.Silhouette Coefficient(輪廓系數(shù)) 適用于被用來(lái)評(píng)估的數(shù)據(jù)沒(méi)有所屬類(lèi)別 同時(shí)兼顧了凝聚度和分散度,取值范圍[-1,1],值越大,聚類(lèi)效果越好
from sklearn.metrics import adjusted_rand_score
print 'The ARI value of KMeans is',adjusted_rand_score(y_test,kmeans_y_predict)
#到此為止,手寫(xiě)體數(shù)字圖像聚類(lèi)--kmeans學(xué)習(xí)結(jié)束,下面單獨(dú)討論輪廓系數(shù)評(píng)價(jià)kmeans的性能
#****************************************************************************************************
#拓展學(xué)習(xí):利用輪廓系數(shù)評(píng)價(jià)不同累簇?cái)?shù)量(k值)的K-means聚類(lèi)實(shí)例
from sklearn.metrics import silhouette_score
#分割出3*2=6個(gè)子圖,并且在1號(hào)子圖作圖 subplot(nrows, ncols, plot_number)
plt.subplot(3,2,1)
#初始化原始數(shù)據(jù)點(diǎn)
x1 = np.array([1,2,3,1,5,6,5,5,6,7,8,9,7,9])
x2 = np.array([1,3,2,2,8,6,7,6,7,1,2,1,1,3])
# a = [1,2,3] b = [4,5,6] zipped = zip(a,b) 輸出為元組的列表[(1, 4), (2, 5), (3, 6)]
X = np.array(zip(x1,x2)).reshape(len(x1),2)
#X輸出為:array([[1, 1],[2, 3],[3, 2],[1, 2],...,[9, 3]])
#在1號(hào)子圖作出原始數(shù)據(jù)點(diǎn)陣的分布
plt.xlim([0,10])
plt.ylim([0,10])
plt.title('Instances')
plt.scatter(x1,x2)
colors = ['b','g','r','c','m','y','k','b']
markers = ['o','s','D','v','^','p','*','+']
clusters = [2,3,4,5,8]
subplot_counter = 1
sc_scores = []
for t in clusters:
subplot_counter += 1
plt.subplot(3,2,subplot_counter)
kmeans_model = KMeans(n_clusters=t).fit(X)
for i,l in enumerate(kmeans_model.labels_):
plt.plot(x1[i],x2[i],color=colors[l],marker=markers[l],ls='None')
plt.xlim([0,10])
plt.ylim([0,10])
sc_score = silhouette_score(X,kmeans_model.labels_,metric='euclidean')
sc_scores.append(sc_score)
#繪制輪廓系數(shù)與不同類(lèi)簇?cái)?shù)量的直觀顯示圖
plt.title('K=%s,silhouette coefficient = %0.03f'%(t,sc_score))
#繪制輪廓系數(shù)與不同類(lèi)簇?cái)?shù)量的關(guān)系曲線
plt.figure() #此處必須空一行,表示在for循環(huán)結(jié)束之后執(zhí)行!??!
plt.plot(clusters,sc_scores,'*-') #繪制折線圖時(shí)的樣子
plt.xlabel('Number of Clusters')
plt.ylabel('Silhouette Coefficient Score')
plt.show()
#****************************************************************************************************
#總結(jié):
#k-means聚類(lèi)模型所采用的迭代式算法,直觀易懂并且非常實(shí)用,但是有兩大缺陷
#1.容易收斂到局部最優(yōu)解,受隨機(jī)初始聚類(lèi)中心影響,可多執(zhí)行幾次k-means來(lái)挑選性能最佳的結(jié)果
#2.需要預(yù)先設(shè)定簇的數(shù)量,