色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

聚類分析經典算法講解及實現

倩倩 ? 來源:網絡整理 ? 2018-02-23 10:54 ? 次閱讀

常用聚類算法比較分析

K-pototypes算法

K-pototypes算法結合了K-means方法和根據K-means方法改進的能夠處理符號屬性的K-modes方法,同K-means方法相比,K-pototypes 算法能夠處理符號屬性。

CLARANS算法(劃分方法)

CLARANS算法即隨機搜索聚類算法,是一種分割聚類方法。它首先隨機選擇一個點作為當前點,然后隨機檢查它周圍不超過參數Maxneighbor 個的一些鄰接點,假如找到一個比它更好的鄰接點,則把它移人該鄰接點,否則把該點作為局部最小量。然后再隨機選擇一個點來尋找另一個局部最小量,直至所找 到的局部最小量數目達到用戶要求為止。該算法要求聚類的對象必須都預先調人內存,并且需多次掃描數據集,這對大數據量而言,無論時間復雜度還是空間復雜度 都相當大。雖通過引人R-樹結構對其性能進行改善,使之能夠處理基于磁盤的大型數據庫,但R*-樹的構造和維護代價太大。該算法對臟數據和異常數據不敏 感,但對數據物人順序異常敏感,且只能處理凸形或球形邊界聚類。

BIRCH算法(層次方法)

BIRCH算法即平衡迭代削減聚類法,其核心是用一個聚類特征3元組表示一個簇的有關信息,從而使一簇點的表示可用對應的聚類特征,而不必用具體的一 組點來表示。它通過構造滿足分支因子和簇直徑限制的聚類特征樹來求聚類。BIRCH算法通過聚類特征可以方便地進行中心、半徑、直徑及類內、類間距離的運 算。算法的聚類特征樹是一個具有兩個參數分枝因子B和類直徑T的高度平衡樹。分枝因子規定了樹的每個節點子女的最多個數,而類直徑體現了對一類點的直徑大 小的限制即這些點在多大范圍內可以聚為一類,非葉子結點為它的子女的最大關鍵字,可以根據這些關鍵字進行插人索引,它總結了其子女的信息。

聚類特征樹可以動態構造,因此不要求所有數據讀人內存,而可以在外存上逐個讀人。新的數據項總是插人到樹中與該數據距離最近的葉子中。如果插人后使得 該葉子的直徑大于類直徑T,則把該葉子節點分裂。其它葉子結點也需要檢查是否超過分枝因子來判斷其分裂與否,直至該數據插入到葉子中,并且滿足不超過類直 徑,而每個非葉子節點的子女個數不大于分枝因子。算法還可以通過改變類直徑修改特征樹大小,控制其占內存容量。

BIRCH算法通過一次掃描就可以進行較好的聚類,由此可見,該算法適合于大數據量。對于給定的M兆內存空間,其空間復雜度為O(M),時間間復雜度 為O(dNBlnB(M/P))。其中d為維數,N為節點數,P為內存頁的大小,B為由P決定的分枝因子。I/O花費與數據量成線性關系。BIRCH算法 只適用于類的分布呈凸形及球形的情況,并且由于BIRCH算法需提供正確的聚類個數和簇直徑限制,對不可視的高維數據不可行。

CURE算法(層次方法)

CURE算法即使用代表點的聚類方法。該算法先把每個數據點看成一類,然后合并距離最近的類直至類個數為所要求的個數為止。CURE算法將傳統對類的 表示方法進行了改進,回避了用所有點或用中心和半徑來表示一個類,而是從每一個類中抽取固定數量、分布較好的點作為描述此類的代表點,并將這些點乘以一個 適當的收縮因子,使它們更靠近類的中心點。將一個類用代表點表示,使得類的外延可以向非球形的形狀擴展,從而可調整類的形狀以表達那些非球形的類。另外, 收縮因子的使用減小了嗓音對聚類的影響。CURE算法采用隨機抽樣與分割相結合的辦法來提高算法的空間和時間效率,并且在算法中用了堆和K-d樹結構來提 高算法效率。

DBSCAN算法(基于密度的方法)

DBSCAN算法即基于密度的聚類算法。該算法利用類的密度連通性可以快速發現任意形狀的類。其基本思想是:對于一個類中的每個對象,在其給定半徑的 領域中包含的對象不能少于某一給定的最小數目。在DBSCAN算法中,發現一個類的過程是基于這樣的事實:一個類能夠被其中的任意一個核心對象所確定。為 了發現一個類,DBSCAN先從對象集D中找到任意一對象P,并查找D中關于關徑Eps和最小對象數Minpts的從P密度可達的所有對象。如果P是核心 對象,即半徑為Eps的P的鄰域中包含的對象不少于Minpts,則根據算法,可以找到一個關于參數Eps和Minpts的類。如果P是一個邊界點,則半 徑為Eps的P鄰域包含的對象少于Minpts,P被暫時標注為噪聲點。然后,DBSCAN處理D中的下一個對象。

密度可達對象的獲取是通過不斷執行區域查詢來實現的。一個區域查詢返回指定區域中的所有對象。為了有效地執行區域查詢,DBSCAN算法使用了空間查 詢R-樹結構。在進行聚類前,必須建立針對所有數據的R*-樹。另外,DBSCAN要求用戶指定一個全局參數Eps(為了減少計算量,預先確定參數 Minpts)。為了確定取值,DBSCAN計算任意對象與它的第k個最臨近的對象之間的距離。然后,根據求得的距離由小到大排序,并繪出排序后的圖,稱 做k-dist圖。k-dist圖中的橫坐標表示數據對象與它的第k個最近的對象間的距離;縱坐標為對應于某一k-dist距離值的數據對象的個數。 R*-樹的建立和k-dist圖的繪制非常消耗時間。此外,為了得到較好的聚類結果,用戶必須根據k-dist圖,通過試探選定一個比較合適的Eps值。 DBSCAN算法不進行任何的預處理而直接對整個數據集進行聚類操作。當數據量非常大時,就必須有大內存量支持,I/O消耗也非常大。其時間復雜度為 O(nlogn)(n為數據量),聚類過程的大部分時間用在區域查詢操作上。DBSCAN算法對參數Eps及Minpts非常敏感,且這兩個參數很難確定。

CLIQUE算法(綜合了基于密度和基于網格的算法)

CLIQUE算法即自動子空間聚類算法。該算法利用自頂向上方法求出各個子空間的聚類單元。CLUQUE算法主要用于找出在高維數據空間中存在的低維 聚類。為了求出d維空間聚類,必須組合給出所有d-1維子空間的聚類,導致其算法的空間和時間效率都較低,而且要求用戶輸入兩個參數:數據取值空間等間隔 距離和密度闊值。這2個參數與樣木數據緊密相關,用戶一般難以確定。CLIQUE算法對數據輸人順序不敏感。

基于上述分析,我們得到各聚類算法的比較結果,結論如下:

聚類分析經典算法講解及實現

K 均值算法詳解及實現

算法流程

K 均值算法,應該是聚類算法中最為基礎但也最為重要的算法。其算法流程如下:

隨機的取 k 個點作為 k 個初始質心;

計算其他點到這個 k 個質心的距離;

如果某個點 p 離第 n 個質心的距離更近,則該點屬于 cluster n,并對其打標簽,標注 point p.label=n,其中 n《=k;

計算同一 cluster 中,也就是相同 label 的點向量的平均值,作為新的質心;

迭代至所有質心都不變化為止,即算法結束。

當然算法實現的方法有很多,比如在選擇初始質心時,可以隨機選擇 k 個,也可以隨機選擇 k 個離得最遠的點等等,方法不盡相同。

K 值估計

對于 k 值,必須提前知道,這也是 kmeans 算法的一個缺點。當然對于 k 值,我們可以有很多種方法進行估計。本文中,我們采用平均直徑法來進行 k 的估計。

也就是說,首先視所有的點為一個大的整體 cluster,計算所有點之間距離的平均值作為該 cluster 的平均直徑。選擇初始質心的時候,先選擇最遠的兩個點,接下來從這最兩個點開始,與這最兩個點距離都很遠的點(遠的程度為,該點到之前選擇的最遠的兩個點的距離都大于整體 cluster 的平均直徑)可視為新發現的質心,否則不視之為質心。設想一下,如果利用平均半徑或平均直徑這一個指標,若我們猜想的 K 值大于或等于真實的 K 值,也就是簇的真實數目,那么該指標的上升趨勢會很緩慢,但是如果我們給出的 K 值小于真實的簇的數目時,這個指標一定會急劇上升。

根據這樣的估算思想,我們就能估計出正確的 k 值,并且得到 k 個初始質心,接著,我們便根據上述算法流程繼續進行迭代,直到所有質心都不變化,從而成功實現算法。如下圖所示:

圖 1. K 值估計

我們知道 k 均值總是收斂的,也就是說,k 均值算法一定會達到一種穩定狀態,在此狀態下,所有的點都不會從一個簇轉移到另一個簇,因此質心不在發生改變。在此,我們引出一個剪枝優化,即:k 均值最明顯的收斂過程會發生在算法運行的前期階段,故在某些情況下為了增加算法的執行效率,我們可以替換上述算法的第五步,采用“迭代至僅有 1%~3%的點在影響質心”或“迭代至僅有 1%~3%的點在改變簇”。

k 均值適用于絕大多數的數據類型,并且簡單有效。但其缺點就是需要知道準確的 k 值,并且不能處理異形簇,比如球形簇,不同尺寸及密度的簇,環形簇等等。

本文主要為算法講解及實現,因此代碼實現暫不考慮面向對象思想,采用面向過程的實現方式,如果數據多維,可能會需要做數據預處理,比如歸一化,并且修改代碼相關方法即可。

算法實現

清單 1. Kmeans 算法代碼實現

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintStream;

import java.text.DecimalFormat;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.PriorityQueue;

import java.util.Queue;

public class Kmeans {

private class Node {

int label;// label 用來記錄點屬于第幾個 cluster

double[] attributes;

public Node() {

attributes = new double[100];

}

}

private class NodeComparator {

Node nodeOne;

Node nodeTwo;

double distance;

public void compute() {

double val = 0;

for (int i = 0; i 《 dimension; ++i) {

val += (this.nodeOne.attributes[i] - this.nodeTwo.attributes[i]) *

(this.nodeOne.attributes[i] - this.nodeTwo.attributes[i]);

}

this.distance = val;

}

}

private ArrayList《Node》 arraylist;

private ArrayList《Node》 centroidList;

private double averageDis;

private int dimension;

private Queue《NodeComparator》 FsQueue =

new PriorityQueue《NodeComparator》(150, // 用來排序任意兩點之間的距離,從大到小排

new Comparator《NodeComparator》() {

public int compare(NodeComparator one, NodeComparator two) {

if (one.distance 《 two.distance)

return 1;

else if (one.distance 》 two.distance)

return -1;

else

return 0;

}

});

public void setKmeansInput(String path) {

try {

BufferedReader br = new BufferedReader(new FileReader(path));

String str;

String[] strArray;

arraylist = new ArrayList《Node》();

while ((str = br.readLine()) != null) {

strArray = str.split(“,”);

dimension = strArray.length;

Node node = new Node();

for (int i = 0; i 《 dimension; ++i) {

node.attributes[i] = Double.parseDouble(strArray[i]);

}

arraylist.add(node);

}

br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

public void computeTheK() {

int cntTuple = 0;

for (int i = 0; i 《 arraylist.size() - 1; ++i) {

for (int j = i + 1; j 《 arraylist.size(); ++j) {

NodeComparator nodecomp = new NodeComparator();

nodecomp.nodeOne = new Node();

nodecomp.nodeTwo = new Node();

for (int k = 0; k 《 dimension; ++k) {

nodecomp.nodeOne.attributes[k] = arraylist.get(i).attributes[k];

nodecomp.nodeTwo.attributes[k] = arraylist.get(j).attributes[k];

}

nodecomp.compute();

averageDis += nodecomp.distance;

FsQueue.add(nodecomp);

cntTuple++;

}

}

averageDis /= cntTuple;// 計算平均距離

chooseCentroid(FsQueue);

}

public double getDistance(Node one, Node two) {// 計算兩點間的歐氏距離

double val = 0;

for (int i = 0; i 《 dimension; ++i) {

val += (one.attributes[i] - two.attributes[i]) * (one.attributes[i] - two.attributes[i]);

}

return val;

}

public void chooseCentroid(Queue《NodeComparator》 queue) {

centroidList = new ArrayList《Node》();

boolean flag = false;

while (!queue.isEmpty()) {

boolean judgeOne = false;

boolean judgeTwo = false;

NodeComparator nc = FsQueue.poll();

if (nc.distance 《 averageDis)

break;// 如果接下來的元組,兩節點間距離小于平均距離,則不繼續迭代

if (!flag) {

centroidList.add(nc.nodeOne);// 先加入所有點中距離最遠的兩個點

centroidList.add(nc.nodeTwo);

flag = true;

} else {// 之后從之前已加入的最遠的兩個點開始,找離這兩個點最遠的點,

// 如果距離大于所有點的平均距離,則認為找到了新的質心,否則不認定為質心

for (int i = 0; i 《 centroidList.size(); ++i) {

Node testnode = centroidList.get(i);

if (centroidList.contains(nc.nodeOne) || getDistance(testnode, nc.nodeOne) 《 averageDis) {

judgeOne = true;

}

if (centroidList.contains(nc.nodeTwo) || getDistance(testnode, nc.nodeTwo) 《 averageDis) {

judgeTwo = true;

}

}

if (!judgeOne) {

centroidList.add(nc.nodeOne);

}

if (!judgeTwo) {

centroidList.add(nc.nodeTwo);

}

}

}

}

public void doIteration(ArrayList《Node》 centroid) {

int cnt = 1;

int cntEnd = 0;

int numLabel = centroid.size();

while (true) {// 迭代,直到所有的質心都不變化為止

boolean flag = false;

for (int i = 0; i 《 arraylist.size(); ++i) {

double dis = 0x7fffffff;

cnt = 1;

for (int j = 0; j 《 centroid.size(); ++j) {

Node node = centroid.get(j);

if (getDistance(arraylist.get(i), node) 《 dis) {

dis = getDistance(arraylist.get(i), node);

arraylist.get(i).label = cnt;

}

cnt++;

}

}

int j = 0;

numLabel -= 1;

while (j 《 numLabel) {

int c = 0;

Node node = new Node();

for (int i = 0; i 《 arraylist.size(); ++i) {

if (arraylist.get(i).label == j + 1) {

for (int k = 0; k 《 dimension; ++k) {

node.attributes[k] += arraylist.get(i).attributes[k];

}

c++;

}

}

DecimalFormat df = new DecimalFormat(“#.###”);// 保留小數點后三位

double[] attributelist = new double[100];

for (int i = 0; i 《 dimension; ++i) {

attributelist[i] = Double.parseDouble(df.format(node.attributes[i] / c));

if (attributelist[i] != centroid.get(j).attributes[i]) {

centroid.get(j).attributes[i] = attributelist[i];

flag = true;

}

}

if (!flag) {

cntEnd++;

if (cntEnd == numLabel) {// 若所有的質心都不變,則跳出循環

break;

}

}

j++;

}

if (cntEnd == numLabel) {// 若所有的質心都不變,則 success

System.out.println(“run kmeans successfully.”);

break;

}

}

}

public void printKmeansResults(String path) {

try {

PrintStream out = new PrintStream(path);

computeTheK();

doIteration(centroidList);

out.println(“There are ” + centroidList.size() + “ clusters!”);

for (int i = 0; i 《 arraylist.size(); ++i) {

out.print(“(”);

for (int j = 0; j 《 dimension - 1; ++j) {

out.print(arraylist.get(i).attributes[j] + “, ”);

}

out.print(arraylist.get(i).attributes[dimension - 1] + “) ”);

out.println(“belongs to cluster ” + arraylist.get(i).label);

}

out.close();

System.out.println(“Please check results in: ” + path);

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

Kmeans kmeans = new Kmeans();

kmeans.setKmeansInput(“c:/kmeans.txt”);

kmeans.printKmeansResults(“c:/kmeansResults.txt”);

}

}

測試數據

給出一組簡單的二維測試數據:

清單 2. Kmeans 算法測試數據

1,1

2,1

1,2

2,2

6,1

6,2

7,1

7,2

1,5

1,6

2,5

2,6

6,5

6,6

7,5

7,6

運行結果

清單 3. Kmeans 算法運行結果

There are 4 clusters!

(1.0, 1.0) belongs to cluster 1

(2.0, 1.0) belongs to cluster 1

(1.0, 2.0) belongs to cluster 1

(2.0, 2.0) belongs to cluster 1

(6.0, 1.0) belongs to cluster 3

(6.0, 2.0) belongs to cluster 3

(7.0, 1.0) belongs to cluster 3

(7.0, 2.0) belongs to cluster 3

(1.0, 5.0) belongs to cluster 4

(1.0, 6.0) belongs to cluster 4

(2.0, 5.0) belongs to cluster 4

(2.0, 6.0) belongs to cluster 4

(6.0, 5.0) belongs to cluster 2

(6.0, 6.0) belongs to cluster 2

(7.0, 5.0) belongs to cluster 2

(7.0, 6.0) belongs to cluster 2

層次聚類算法詳解及實現

層次聚類簡介

層次聚類分為凝聚式層次聚類和分裂式層次聚類。

凝聚式層次聚類,就是在初始階段將每一個點都視為一個簇,之后每一次合并兩個最接近的簇,當然對于接近程度的定義則需要指定簇的鄰近準則。

分裂式層次聚類,就是在初始階段將所有的點視為一個簇,之后每次分裂出一個簇,直到最后剩下單個點的簇為止。

本文中我們將詳細介紹凝聚式層次聚類算法。

對于凝聚式層次聚類,指定簇的鄰近準則是非常重要的一個環節,在此我們介紹三種最常用的準則,分別是 MAX, MIN, 組平均。如下圖所示:

圖 2. 層次聚類計算準則

凝聚式層次聚類算法也是一個迭代的過程,算法流程如下:

每次選最近的兩個簇合并,我們將這兩個合并后的簇稱之為合并簇。

若采用 MAX 準則,選擇其他簇與合并簇中離得最遠的兩個點之間的距離作為簇之間的鄰近度。若采用 MIN 準則,取其他簇與合并簇中離得最近的兩個點之間的距離作為簇之間的鄰近度。若組平均準則,取其他簇與合并簇所有點之間距離的平均值作為簇之間的鄰近度。

重復步驟 1 和步驟 2,合并至只剩下一個簇。

算法過程舉例

下面我們看一個例子:

下圖是一個有五個點的而為坐標系:

圖 3. 層次聚類舉例

聚類分析經典算法講解及實現

下表為這五個點的歐式距離矩陣:

表 1. 歐式距離原始矩陣

聚類分析經典算法講解及實現

根據算法流程,我們先找出距離最近的兩個簇,P3, P4。

合并 P3, P4 為 {P3, P4},根據 MIN 原則更新矩陣如下:

MIN.distance({P3, P4}, P1) = 1.32;

MIN.distance({P3, P4}, P2) = 1.56;

MIN.distance({P3, P4}, P5) = 0.70;

表 2. 歐式距離更新矩陣 1

聚類分析經典算法講解及實現

接著繼續找出距離最近的兩個簇,{P3, P4}, P5。

合并 {P3, P4}, P5 為 {P3, P4, P5},根據 MIN 原則繼續更新矩陣:

MIN.distance(P1, {P3, P4, P5}) = 1.32;

MIN.distance(P2, {P3, P4, P5}) = 1.56;

表 3. 歐式距離更新矩陣 2

聚類分析經典算法講解及實現

接著繼續找出距離最近的兩個簇,P1, P2。

合并 P1, P2 為 {P1, P2},根據 MIN 原則繼續更新矩陣:

MIN.distance({P1,P2}, {P3, P4, P5}) = 1.32

表 4. 歐式距離更新矩陣 3

聚類分析經典算法講解及實現

最終合并剩下的這兩個簇即可獲得最終結果,如下圖:

圖 4. 層次聚類舉例結果

聚類分析經典算法講解及實現

MAX,組平均算法流程同理,只是在更新矩陣時將上述計算簇間距離變為簇間兩點最大歐式距離,和簇間所有點平均歐式距離即可。

算法實現

清單 4. 層次聚類算法代碼實現

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintStream;

import java.text.DecimalFormat;

import java.util.ArrayList;

public class Hierarchical {

private double[][] matrix;

private int dimension;// 數據維度

private class Node {

double[] attributes;

public Node() {

attributes = new double[100];

}

}

private ArrayList《Node》 arraylist;

private class Model {

int x = 0;

int y = 0;

double value = 0;

}

private Model minModel = new Model();

private double getDistance(Node one, Node two) {// 計算兩點間的歐氏距離

double val = 0;

for (int i = 0; i 《 dimension; ++i) {

val += (one.attributes[i] - two.attributes[i]) * (one.attributes[i] - two.attributes[i]);

}

return Math.sqrt(val);

}

private void loadMatrix() {// 將輸入數據轉化為矩陣

for (int i = 0; i 《 matrix.length; ++i) {

for (int j = i + 1; j 《 matrix.length; ++j) {

double distance = getDistance(arraylist.get(i), arraylist.get(j));

matrix[i][j] = distance;

}

}

}

private Model findMinValueOfMatrix(double[][] matrix) {// 找出矩陣中距離最近的兩個簇

Model model = new Model();

double min = 0x7fffffff;

for (int i = 0; i 《 matrix.length; ++i) {

for (int j = i + 1; j 《 matrix.length; ++j) {

if (min 》 matrix[i][j] && matrix[i][j] != 0) {

min = matrix[i][j];

model.x = i;

model.y = j;

model.value = matrix[i][j];

}

}

}

return model;

}

private void processHierarchical(String path) {

try {

PrintStream out = new PrintStream(path);

while (true) {// 凝聚層次聚類迭代

out.println(“Matrix update as below: ”);

for (int i = 0; i 《 matrix.length; ++i) {// 輸出每次迭代更新的矩陣

for (int j = 0; j 《 matrix.length - 1; ++j) {

out.print(new DecimalFormat(“#.00”).format(matrix[i][j]) + “ ”);

}

out.println(new DecimalFormat(“#.00”).format(matrix[i][matrix.length - 1]));

}

out.println();

minModel = findMinValueOfMatrix(matrix);

if (minModel.value == 0) {// 當找不出距離最近的兩個簇時,迭代結束

break;

}

out.println(“Combine ” + (minModel.x + 1) + “ ” + (minModel.y + 1));

out.println(“The distance is: ” + minModel.value);

matrix[minModel.x][minModel.y] = 0;// 更新矩陣

for (int i = 0; i 《 matrix.length; ++i) {// 如果合并了點 p1 與 p2,則只保留 p1,p2 其中之一與其他點的距離,取較小值

if (matrix[i][minModel.x] 《= matrix[i][minModel.y]) {

matrix[i][minModel.y] = 0;

} else {

matrix[i][minModel.x] = 0;

}

if (matrix[minModel.x][i] 《= matrix[minModel.y][i]) {

matrix[minModel.y][i] = 0;

} else {

matrix[minModel.x][i] = 0;

}

}

}

out.close();

System.out.println(“Please check results in: ” + path);

} catch (Exception e) {

e.printStackTrace();

}

}

public void setInput(String path) {

try {

BufferedReader br = new BufferedReader(new FileReader(path));

String str;

String[] strArray;

arraylist = new ArrayList《Node》();

while ((str = br.readLine()) != null) {

strArray = str.split(“,”);

dimension = strArray.length;

Node node = new Node();

for (int i = 0; i 《 dimension; ++i) {

node.attributes[i] = Double.parseDouble(strArray[i]);

}

arraylist.add(node);

}

matrix = new double[arraylist.size()][arraylist.size()];

loadMatrix();

br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

public void printOutput(String path) {

processHierarchical(path);

}

public static void main(String[] args) {

Hierarchical hi = new Hierarchical();

hi.setInput(“c:/hierarchical.txt”);

hi.printOutput(“c:/hierarchical_results.txt”);

}

}

測試數據

給出一組簡單的二維測試數據

清單 5. 層次聚類算法測試數據

0.7,1.2

0.8,2

2,1

2.6,0.8

2.5,1.5

運行結果

清單 6. 層次聚類算法運行結果

Matrix update as below:

.00 .81 1.32 1.94 1.82

.00 .00 1.56 2.16 1.77

.00 .00 .00 .63 .71

.00 .00 .00 .00 .71

.00 .00 .00 .00 .00

Combine 3 4

The distance is: 0.6324555320336759

Matrix update as below:

.00 .81 1.32 .00 1.82

.00 .00 1.56 .00 1.77

.00 .00 .00 .00 .00

.00 .00 .00 .00 .71

.00 .00 .00 .00 .00

Combine 4 5

The distance is: 0.7071067811865475

Matrix update as below:

.00 .81 1.32 .00 .00

.00 .00 1.56 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

Combine 1 2

The distance is: 0.806225774829855

Matrix update as below:

.00 .00 1.32 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

Combine 1 3

The distance is: 1.3152946437965907

Matrix update as below:

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

.00 .00 .00 .00 .00

DBSCAN 算法詳解及實現

考慮一種情況,點的分布不均勻,形狀不規則時,Kmeans 算法及層次聚類算法將面臨失效的風險。

如下坐標系:

圖 5. DBSCAN 算法舉例

聚類分析經典算法講解及實現

我們可以看到上面的點密度不均勻,這時我們考慮采用基于密度的聚類算法:DBSCAN。

算法流程

設定掃描半徑 Eps, 并規定掃描半徑內的密度值。若當前點的半徑范圍內密度大于等于設定密度值,則設置當前點為核心點;若某點剛好在某核心點的半徑邊緣上,則設定此點為邊界點;若某點既不是核心點又不是邊界點,則此點為噪聲點。

刪除噪聲點。

將距離在掃描半徑內的所有核心點賦予邊進行連通。

每組連通的核心點標記為一個簇。

將所有邊界點指定到與之對應的核心點的簇總。

算法過程舉例

如上圖坐標系所示,我們設定掃描半徑 Eps 為 1.5,密度閾值 threshold 為 3,則通過上述算法過程,我們可以得到下圖:

圖 6. DBSCAN 算法舉例結果示例

聚類分析經典算法講解及實現

通過計算各個點之間的歐式距離及其所在掃描半徑內的密度值來判斷這些點屬于核心點,邊界點或是噪聲點。因為我們設定了掃描半徑為 1.5,密度閾值為 3,所以:

P0 點為邊界點,因為在以其為中心的掃描半徑內只有兩個點 P0 和 P1;

P1 點為核心點,因為在以其為中心的掃描半徑內有四個點 P0,P1,P2,P4 ;

P8 為噪聲點,因為其既非核心點,也非邊界點;

其他點依次類推。

算法實現

清單 7. DBSCAN 算法代碼實現

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintStream;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

public class DBSCAN {

private int dimension;// 數據維度

private double eps = 1.5;

private int threshold = 3;

private double distance[][];

private Map《Integer, Integer》 id = new HashMap《Integer, Integer》();

private int countClusters = 0;

private ArrayList《Integer》 keyPointList = new ArrayList《Integer》();//

private int[] flags;// 標記邊緣點

private class Edge {

int p, q;

double weight;

}

private class Node {

double[] attributes;

public Node() {

attributes = new double[100];

}

}

private ArrayList《Node》 nodeList;

private ArrayList《Edge》 edgeList;

private double getDistance(Node one, Node two) {// 計算兩點間的歐氏距離

double val = 0;

for (int i = 0; i 《 dimension; ++i) {

val += (one.attributes[i] - two.attributes[i]) * (one.attributes[i] - two.attributes[i]);

}

return Math.sqrt(val);

}

public void loadEdges() {// 給所有在掃描半徑內的核心點之間加邊,標記邊界點并且自動忽略噪聲點

edgeList = new ArrayList《Edge》();

flags = new int[nodeList.size()];

int[] countPoint = new int[nodeList.size()];

for (int i = 0; i 《 countPoint.length; ++i) {

countPoint[i] = 1;// 每一個點一開始都是核心點

}

for (int i = 0; i 《 nodeList.size(); ++i) {

for (int j = i + 1; j 《 nodeList.size(); ++j) {

distance[i][j] = getDistance(nodeList.get(i), nodeList.get(j));

if (distance[i][j] 《= eps) {// 兩點間距離小于掃描半徑

countPoint[i]++;

if (countPoint[i] 》 0 && countPoint[i] 《 threshold) {

flags[i] = j;// 記錄邊界點

}

if (countPoint[i] 》= threshold) {// 如果記錄當前點的掃描半徑內密度值大于或等于給定閾值

flags[i] = 0;

if (!keyPointList.contains(i)) {

keyPointList.add(i);

}

}

countPoint[j]++;

if (countPoint[j] 》 0 && countPoint[j] 《 threshold) {

flags[j] = i;// 記錄邊界點

}

if (countPoint[j] 》= threshold) {// 如果記錄當前點的掃描半徑內密度值大于或等于給定閾值

flags[j] = 0;

if (!keyPointList.contains(j)) {

keyPointList.add(j);

}

}

}

}

}

for (int i = 0; i 《 keyPointList.size(); ++i) {

for (int j = i + 1; j 《 keyPointList.size(); ++j) {

Edge edge = new Edge();

edge.p = keyPointList.get(i);

edge.q = keyPointList.get(j);

edge.weight = distance[edge.p][edge.q];

if (edge.weight 《= eps) {

if (!id.containsKey(edge.p)) {// 為后期使用并查集求連通分量做準備

id.put(edge.p, edge.p);

}

if (!id.containsKey(edge.q)) {

id.put(edge.q, edge.q);

}

edgeList.add(edge);

}

}

}

}

public void setInput(String path) {

try {

BufferedReader br = new BufferedReader(new FileReader(path));

String str;

String[] strArray;

nodeList = new ArrayList《Node》();

while ((str = br.readLine()) != null) {

strArray = str.split(“,”);

dimension = strArray.length;

Node node = new Node();

for (int i = 0; i 《 dimension; ++i) {

node.attributes[i] = Double.parseDouble(strArray[i]);

}

nodeList.add(node);

}

distance = new double[nodeList.size()][nodeList.size()];

loadEdges();

br.close();

} catch (IOException e) {

e.printStackTrace();

}

}

public void union(int p, int q) {// 并操作

int a = find(p);

int b = find(q);

if (a != b) {

id.put(a, b);

}

}

public int find(int p) {// 查操作

if (p != id.get(p)) {

id.put(p, find(id.get(p)));

}

return id.get(p);

}

public void processDBSCAN(String path) {

try {

PrintStream out = new PrintStream(path);

out.println(“核心點為: ” + keyPointList);

out.println();

for (int i = 0; i 《 edgeList.size(); ++i) {

out.println(“核心點 (” + edgeList.get(i).p + “ ” +

edgeList.get(i).q + “) 之間的距離為: ” + edgeList.get(i).weight);

}

for (int i = 0; i 《 edgeList.size(); ++i) {

union(edgeList.get(i).p, edgeList.get(i).q);// 利用并查集將點集變為連通分量

}

Iterator《Integer》 it = id.keySet().iterator();

while (it.hasNext()) {

int key = it.next();

if (id.get(key) == key) {// 利用并查集得到強連通分量個數

++countClusters;

}

}

out.println();

for (int i = 0; i 《 flags.length; ++i) {

if (flags[i] != 0) {

out.println(“點” + i + “屬于點” + flags[i] + “所在的簇”);

}

}

out.println();

out.println(“由核心點連通分量數量得知共有: ” + countClusters + “個簇”);

out.close();

System.out.println(“Please check results in: ” + path);

} catch (Exception e) {

e.printStackTrace();

}

}

public void printOutput(String path) {

processDBSCAN(path);

}

public static void main(String[] args) {

DBSCAN dbscan = new DBSCAN();

dbscan.setInput(“c:/dbscan.txt”);

dbscan.printOutput(“c:/dbscan_results.txt”);

}

}

測試數據

清單 8. DBSCAN 算法測試數據

2,1

2,2

2,3

3,3

3,4.5

4,1

4,2

4,3

6,2

8,1

8,2

8,3

9,1

10,1

10,2

10,3

運行結果

清單 9. DBSCAN 算法運行結果

核心點為: [1, 2, 3, 6, 7, 9, 10, 12, 13, 14]

核心點 (1 2) 之間的距離為: 1.0

核心點 (1 3) 之間的距離為: 1.4142135623730951

核心點 (2 3) 之間的距離為: 1.0

核心點 (3 6) 之間的距離為: 1.4142135623730951

核心點 (3 7) 之間的距離為: 1.0

核心點 (6 7) 之間的距離為: 1.0

核心點 (9 10) 之間的距離為: 1.0

核心點 (9 12) 之間的距離為: 1.0

核心點 (10 12) 之間的距離為: 1.4142135623730951

核心點 (12 13) 之間的距離為: 1.0

核心點 (12 14) 之間的距離為: 1.4142135623730951

核心點 (13 14) 之間的距離為: 1.0

連通點 1 和點 2

連通點 1 和點 3

連通點 3 和點 6

連通點 3 和點 7

連通點 9 和點 10

連通點 9 和點 12

連通點 12 和點 13

連通點 12 和點 14

點 1、點 2、點 3、點 6、點 7 同屬于簇 1

點 9、點 10、點 12、點 13、點 14 同屬于簇 2

點 0 屬于點 1 所在的簇

點 4 屬于點 3 所在的簇

點 5 屬于點 6 所在的簇

點 11 屬于點 10 所在的簇

點 15 屬于點 14 所在的簇

由核心點連通分量數量得知共有: 2 個簇

其他聚類算法簡介

BIRCH 算法

Birch 是一種能夠高效處理大數據聚類的基于樹的層次聚類算法。設想這樣一種情況,一個擁有大規模數據的數據庫,當這些數據被放入主存進行聚類處理時,一般的聚類算法則沒有對應的高效處理能力,這時 Birch 算法是最佳的選擇。

Birth 不僅能夠高效地處理大數據聚類,并且能最小化 IO 花銷。它不需要掃描全局數據已經現有的簇。

算法流程

聚類特征 CF=(N,LS,SS),其中 N 代表簇中點的個數,LS 代表簇中代表簇中各點線性和,SS 代表簇中各點的平方和距離。聚類特征被應用于 CF 樹中,CF 樹是一種高度平衡樹,它具有兩個參數:平衡因子 B 和簇半徑閾值 T。其中平衡因子 B 代表每一個非葉子節點最多能夠引入 B 個實體條目。

葉子節點最多只能包含 L 個實體條目,并且它們具有前向后向指針,這樣可以彼此鏈接起來。

樹的大小取決于簇半徑閾值 T 的大小。

從根節點開始,遞歸查找與要插入的數據點距離最近的葉子節點中的實體條目,遞歸過程選擇最短路徑。

比較上述計算出的數據點與葉子節點中實體條目間的最近距離是否小葉簇半徑閾值 T,小于則吸收該數據點。否則執行下一步。

判斷當前條目所在的葉節點個數是否小于 L,若小于則直接將該數據點插入當前點。否則分裂葉子節點,分裂過程是將葉子節點中距離最遠的兩個實體條目變為新的兩個葉子節點,其他條目則根據距離最近原則重新分配到這兩個新的葉子節點中。刪除原來的葉子節點并更新 CF 樹。

若不能將所有數據點加入 CF 樹中,則考慮增加簇半徑閾值 T,并重新更新 CF 樹直至所有的數據點被加入 CF 樹為止。

CURE 算法

算法流程

在數據集中選擇樣本數據。

將上述樣本數據劃分為 P 個同樣大小的劃分。

將每個劃分中的點聚成 m/pq 個簇,共得到 m/q 個簇。過程中需刪除噪聲點。

對上述 m/q 個簇進行聚類直至剩下 k 個簇。

繼續刪除離群點。

將剩下的點指派到最近的簇完成聚類過程。

聚類算法是數據挖掘算法中最為重要的部分之一,算法種類繁多,應用場景也各有不同,本文章提到的聚類算法為常見常用的一些較為基本的算法,對于其他的聚類算法,如最小生成樹聚類,CLIQUE,DENCLUE,SOM 等等如有興趣,讀者可以自行查找相關資料進行學習。本文旨在提高讀者對算法本身的理解,代碼實現過程及結果打印能夠更好的幫助讀者剖析算法,使讀者能夠更快的入門并掌握基本的聚類算法。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 聚類分析
    +關注

    關注

    0

    文章

    16

    瀏覽量

    7413
收藏 人收藏

    評論

    相關推薦

    Matlab提供的兩種聚類分析

    Matlab提供的兩種聚類分析提供源程序代碼
    發表于 04-29 11:21

    實用算法分析與程序設計

    實用算法分析與程序設計全書不僅從教學的角度詳細講解算法的理論,而且從競賽的角度對經典習題進行詳細解析,重在培養學生靈活運用
    發表于 10-23 22:57 ?0次下載
    實用<b class='flag-5'>算法</b><b class='flag-5'>分析</b>與程序設計

    星座圖聚類分析的QAM信號調制識別算法及DSP實現

    星座圖聚類分析的QAM信號調制識別算法及DSP實現 本文首先討論基于信號星座圖聚類分析的QAM信號識別算法,接著對TS201芯片進行了簡介
    發表于 05-08 08:28 ?2788次閱讀
    星座圖<b class='flag-5'>聚類分析</b>的QAM信號調制識別<b class='flag-5'>算法</b>及DSP<b class='flag-5'>實現</b>

    基于GT4的聚類分析算法研究

    本論文的研究視角是當前比較熱門的兩個問題:網格技術和數據挖掘技術。將網格計算和數據挖掘技術結合起來,開發基于網格的數據系統,借鑒傳統聚類分析算法CLUQ和K_平均值算法,設計基于網格的全局和局部
    發表于 02-13 15:21 ?1015次閱讀

    基于主動學習的微博聚類分析

    基于主動學習的微博聚類分析_朱麗
    發表于 01-07 16:24 ?0次下載

    一種擬人聚類算法在PHM聚類分析中的應用

    一種擬人聚類算法在PHM聚類分析中的應用_賀呈磊
    發表于 01-07 21:39 ?0次下載

    基于Hadoop與聚類分析的網絡日志分析模型

    ;利用HDFS結合的方式對數據進行存儲;利用聚類分析算法構建web日志分析模型,對用戶行為進行分析。最后通過搭建Hadoop測試環境對日志分析
    發表于 12-07 15:40 ?0次下載
    基于Hadoop與<b class='flag-5'>聚類分析</b>的網絡日志<b class='flag-5'>分析</b>模型

    spss聚類分析樹狀圖

    借助主成分得分對河南省各市進行聚類分析。在進行聚類分析時,指標越多就會使樣品間的共性顯示得越少,太多的指標會使計算出的樣品間的距離偏大,從而不利于樣品間相似性的綜合和聚類分析的進行,往往達不到所想
    的頭像 發表于 02-12 15:59 ?4.8w次閱讀

    聚類分析方法有哪些

    目前,聚類問題的研究不僅僅局限于上述的硬聚類,即每一個數據只能被歸為一類,模糊聚類[10]也是聚類分析中研究較為廣泛的一個分支。模糊聚類通過隸屬函數來確定每個數據隸屬于各個簇的程度,而不是將一個數
    的頭像 發表于 02-23 10:36 ?1.8w次閱讀

    聚類分析方法有什么好處

    近些年來,數值分類學逐漸形成了一個新的分支,稱為聚類分析,聚類分析適用于很多不同類型的數據集合,很多研究領域,如工程、生物、醫藥、語言、人類學、心理學和市場學等,都對聚類技術的發展和應用起到了推動作用。
    的頭像 發表于 02-23 11:16 ?3.4w次閱讀

    基于FPGA的定點LMS算法實現講解

    基于FPGA的定點LMS算法實現講解
    發表于 04-28 11:17 ?14次下載

    基于Python的聚類分析及其應用簡介

    基于Python的聚類分析及其應用簡介。
    發表于 05-28 10:54 ?8次下載

    可對海量高維數據進行有效的聚類分析算法

    隨著大數據時代的來臨,如何對海量高維數據進行有效的聚類分析并充分利用,已成為當下的熱門研究課題。傳統的聚類算法在處理高維數據時,聚類結果的精確度和穩定性較低,而子空間聚類算法通過分割原始數據的特征
    發表于 05-28 16:26 ?0次下載

    可對海量高維數據進行有效的聚類分析算法

    隨著大數據時代的來臨,如何對海量高維數據進行有效的聚類分析并充分利用,已成為當下的熱門研究課題。傳統的聚類算法在處理高維數據時,聚類結果的精確度和穩定性較低,而子空間聚類算法通過分割原始數據的特征
    發表于 05-28 16:26 ?3次下載

    機器學習之分類分析聚類分析

    數據挖掘中應用較多的技術機器學習。機器學習主流算法包括三種:關聯分析、分類分析聚類分析
    的頭像 發表于 03-27 14:13 ?4984次閱讀
    主站蜘蛛池模板: 欧美麻豆一精品一AV一免费| 亚洲福利电影一区二区?| 在线a视频| 蜜柚影院在线观看免费高清中文| 91九色精品国产免费| 欧洲另类一二三四区| 国产精品路线1路线2路线| 亚洲人成在线播放网站岛国| 免费看国产精品麻豆| 成人伦理影院| 亚洲色图p| 前后灌满白浆护士| 国内精品自产拍在线少密芽| 91羞羞视频| 无码人妻精品一区二区蜜桃色欲 | 97伦理97伦理2018最新| 色戒床震视频片段| 久久草这在线观看免费| www.av在线| 亚洲乱码中文字幕久久孕妇黑人| 美女露100%全身无遮挡| 国产精品色无码AV在线观看| 做暧暧免费30秒体验| 天天久久影视色香综合网| 狂野猛交xxxx吃奶| 国产精品野外AV久久久| 99精品国产第一福利网站| 无码天堂亚洲国产AV久久| 免费视频不卡| 韩国甜性涩爱| 打扑克床上视频不用下载免费观看 | 亚洲二区电影| 琪琪热热色原日韩在线| 精品无码国产自产在线观看水浒传| 不卡人妻无码AV中文系列APP| 夜色资源站国产www在线视频| 日本无码专区亚洲麻豆| 麻豆精品人妻一区二区三区蜜桃 | 小妇人电影免费完整观看2021| 免费人成网站在线观看10分钟| 國產日韓亞洲精品AV|