聚類就是對大量未知標注的數據集,按照數據內部存在的數據特征將數據集划分為多個不同的類別,使類別內的數據比較相似,類別之間的數據相似度比較小;屬於無監督學習。
算法步驟
1.初始化的k個中心點
2.為每個樣本根據距離分配類別
3.更新每個類別的中心點(更新為該類別的所有樣本的均值)
4.重復上面兩步操作,直到達到某個中止條件
層次聚類方法對給定的數據集進行層次的分解,直到滿足某種條件為止,傳統的層次聚類算法主要分為兩大類算法:
凝聚的層次聚類
AGNES算法==>采用自底向上的策略。
agglomerative(凝聚) nesting(嵌套)
最初將每個對象作為一個簇,然后這些簇根據某些准則(兩個簇之間的相似度度量方式)被一步一步合並,兩個簇間的距離可以由這兩個不同簇中距離最近的數據點的相似度來確定;聚類的合並過程反復進行直到所有的對象滿足簇數目。
AGNES就是把每個水果當成一個類別,然后再進行聚類。
合並點的選擇:
-
兩個簇間的最大距離(complete)
-
兩個簇間的最小距離(word)
-
兩個簇間的平均距離(average)
適合鏈式的聚類,條狀的就比較適合。
代碼:
linkages :complete,word,average
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt # 調用AGNES from sklearn.cluster import AgglomerativeClustering from sklearn.neighbors import kneighbors_graph ## KNN的K近鄰計算 import sklearn.datasets as ds # 攔截異常信息 import warnings warnings.filterwarnings('ignore') # 設置屬性防止中文亂碼 mpl.rcParams['font.sans-serif'] = [u'SimHei'] mpl.rcParams['axes.unicode_minus'] = False # 模擬數據產生: 產生600條數據 np.random.seed(0) n_clusters = 4 N = 1000 data1, y1 = ds.make_blobs(n_samples=N, n_features=2, centers=((-1, 1), (1, 1), (1, -1), (-1, -1)), random_state=0) n_noise = int(0.1 * N) r = np.random.rand(n_noise, 2) min1, min2 = np.min(data1, axis=0) max1, max2 = np.max(data1, axis=0) r[:, 0] = r[:, 0] * (max1 - min1) + min1 r[:, 1] = r[:, 1] * (max2 - min2) + min2 data1_noise = np.concatenate((data1, r), axis=0) y1_noise = np.concatenate((y1, [4] * n_noise)) # 擬合月牙形數據 data2, y2 = ds.make_moons(n_samples=N, noise=.05) data2 = np.array(data2) n_noise = int(0.1 * N) r = np.random.rand(n_noise, 2) min1, min2 = np.min(data2, axis=0) max1, max2 = np.max(data2, axis=0) r[:, 0] = r[:, 0] * (max1 - min1) + min1 r[:, 1] = r[:, 1] * (max2 - min2) + min2 data2_noise = np.concatenate((data2, r), axis=0) y2_noise = np.concatenate((y2, [3] * n_noise)) def expandBorder(a, b): d = (b - a) * 0.1 return a - d, b + d ## 畫圖 # 給定畫圖的顏色 cm = mpl.colors.ListedColormap(['#FF0000', '#00FF00', '#0000FF', '#d8e507', '#F0F0F0']) plt.figure(figsize=(14, 12), facecolor='w') linkages = ("ward", "complete", "average") # 把幾種距離方法,放到list里,后面直接循環取值 for index, (n_clusters, data, y) in enumerate(((4, data1, y1), (4, data1_noise, y1_noise), (2, data2, y2), (2, data2_noise, y2_noise))): # 前面的兩個4表示幾行幾列,第三個參數表示第幾個子圖(從1開始,從左往右數) plt.subplot(4, 4, 4 * index + 1) plt.scatter(data[:, 0], data[:, 1], c=y, cmap=cm) plt.title(u'原始數據', fontsize=17) plt.grid(b=True, ls=':') min1, min2 = np.min(data, axis=0) max1, max2 = np.max(data, axis=0) plt.xlim(expandBorder(min1, max1)) plt.ylim(expandBorder(min2, max2)) # 計算類別與類別的距離(只計算最接近的七個樣本的距離) -- 希望在agens算法中,在計算過程中不需要重復性的計算點與點之間的距離 connectivity = kneighbors_graph(data, n_neighbors=7, mode='distance', metric='minkowski', p=2, include_self=True) connectivity = (connectivity + connectivity.T) for i, linkage in enumerate(linkages): ##進行建模,並傳值 ac = AgglomerativeClustering(n_clusters=n_clusters, affinity='euclidean', connectivity=connectivity, linkage=linkage) ac.fit(data) y = ac.labels_ plt.subplot(4, 4, i + 2 + 4 * index) plt.scatter(data[:, 0], data[:, 1], c=y, cmap=cm) plt.title(linkage, fontsize=17) plt.grid(b=True, ls=':') plt.xlim(expandBorder(min1, max1)) plt.ylim(expandBorder(min2, max2)) plt.tight_layout(0.5, rect=(0, 0, 1, 0.95)) plt.show()
AGNES使用不同合並方式的結果:
分裂的層次聚類(類似於決策樹)
DIANA算法==>采用自頂向下的策略。
divisive(分裂) analysis(分析)
首先將所有對象置於一個簇中,然后按照某種既定的規則逐漸細分為越來越小的簇(比如利用kmeans),直到達到某個終結條件(簇數目或者簇距離達到閾值)。
1,將所有樣本數據作為一個簇放到一個隊列中2,划分為兩個子簇(初始化兩個中心點進行聚類),並將子簇添加到隊列中3,循環迭代第二步操作,直到中止條件達到(聚簇數量、最小平方誤差、迭代次數)
分割點的選擇:
-
各自簇的誤差
-
各自簇的SSE(優選這種策略)
-
選擇樣本數據量最多的簇
DIANA類似於分面包
AGNES和DIANA
-
簡單,理解容易
-
合並點/分裂點選擇不太容易
-
合並/分類的操作不能進行撤銷(面包切開就合不上了)
-
大數據集不太適合
-
執行效率較低O(t*n2),t為迭代次數,n為樣本點數
AGNES的優化
BIRCH(掌握)
BIRCH算法(平衡迭代削減聚類法):
聚類特征使用3元組進行一個簇的相關信息,通過構建滿足分枝因子和簇直徑限制的聚類特征樹來求聚類,聚類特征樹其實是一個具有兩個參數分枝因子和類直徑的高度平衡樹;分枝因子規定了樹的每個節點的子女的最多個數,而類直徑體現了對這一類點的距離范圍;非葉子節點為它子女的最大特征值;
聚類特征樹的構建可以是動態過程的,可以隨時根據數據對模型進行更新操作。
從根節點到葉子節點一層一層的取判斷,
優缺點:
-
適合大規模數據集,線性效率;
-
只適合分布呈凸形或者球形的數據集、需要給定聚類個數和簇之間的相關參數
代碼實現:
庫參數:
-
threshold 類直徑
-
branshing_factor 分支因子
-
n_clusters 簇個數
from itertools import cycle from time import time import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.colors as colors from sklearn.cluster import Birch from sklearn.datasets.samples_generator import make_blobs ## 設置屬性防止中文亂碼 mpl.rcParams['font.sans-serif'] = [u'SimHei'] mpl.rcParams['axes.unicode_minus'] = False ## 產生模擬數據 xx = np.linspace(-22, 22, 10) yy = np.linspace(-22, 22, 10) xx, yy = np.meshgrid(xx, yy) n_centres = np.hstack((np.ravel(xx)[:, np.newaxis], np.ravel(yy)[:, np.newaxis])) # 產生10萬條特征屬性是2,類別是100,符合高斯分布的數據集 X, y = make_blobs(n_samples=100000, n_features=2, centers=n_centres, random_state=28) # 創建不同的參數(簇直徑)Birch層次聚類 birch_models = [ Birch(threshold=1.7, n_clusters=None), Birch(threshold=0.5, n_clusters=None), Birch(threshold=1.7, n_clusters=100) ] # threshold:簇直徑的閾值, branching_factor:大葉子個數 # 我們也可以加參數來試一下效果,比如加入分支因子branching_factor,給定不同的參數值,看聚類的結果 ## 畫圖 final_step = [u'直徑=1.7;n_lusters=None', u'直徑=0.5;n_clusters=None', u'直徑=1.7;n_lusters=100'] plt.figure(figsize=(12, 8), facecolor='w') plt.subplots_adjust(left=0.02, right=0.98, bottom=0.1, top=0.9) colors_ = cycle(colors.cnames.keys()) cm = mpl.colors.ListedColormap(colors.cnames.keys()) for ind, (birch_model, info) in enumerate(zip(birch_models, final_step)): t = time() birch_model.fit(X) time_ = time() - t # 獲取模型結果(label和中心點) labels = birch_model.labels_ centroids = birch_model.subcluster_centers_ n_clusters = len(np.unique(centroids)) print("Birch算法,參數信息為:%s;模型構建消耗時間為:%.3f秒;聚類中心數目:%d" % (info, time_, len(np.unique(labels)))) # 畫圖 subinx = 221 + ind plt.subplot(subinx) for this_centroid, k, col in zip(centroids, range(n_clusters), colors_): mask = labels == k plt.plot(X[mask, 0], X[mask, 1], 'w', markerfacecolor=col, marker='.') if birch_model.n_clusters is None: plt.plot(this_centroid[0], this_centroid[1], '*', markerfacecolor=col, markeredgecolor='k', markersize=2) plt.ylim([-25, 25]) plt.xlim([-25, 25]) plt.title(u'Birch算法%s,耗時%.3fs' % (info, time_)) plt.grid(False) # 原始數據集顯示 plt.subplot(224) plt.scatter(X[:, 0], X[:, 1], c=y, s=1, cmap=cm, edgecolors='none') plt.ylim([-25, 25]) plt.xlim([-25, 25]) plt.title(u'原始數據') plt.grid(False) plt.show()
運行結果:
Birch算法,參數信息為:直徑=1.7;n_lusters=None;模型構建消耗時間為:2.510秒;聚類中心數目:171Birch算法,參數信息為:直徑=0.5;n_clusters=None;模型構建消耗時間為:6.689秒;聚類中心數目:3205Birch算法,參數信息為:直徑=1.7;n_lusters=100;模型構建消耗時間為:3.013秒;聚類中心數目:100
Process finished with exit code 0
import pandas as pd from sklearn.cluster import AgglomerativeClustering import scipy.cluster.hierarchy as sch import matplotlib.pyplot as plt data = pd.read_excel("input/business_circle.xls") print(data.head()) # 要求根據以上維度指標,對數據集進行層次聚類,並找出潛在的顧客分布規律, agnes = AgglomerativeClustering(n_clusters=3, affinity="euclidean", linkage='ward') agnes.fit(data) # 同時要求打印輸出樣本的類別標簽, print(agnes.labels_) # 並畫出譜系聚類圖。 model = sch.linkage(data,method="ward",metric="euclidean") sch.dendrogram(model) plt.show()
CURE(沒人用)
CURE算法(使用代表點的聚類法):
該算法先把每個數據點看成一類,然后合並距離最近的類直至類個數為所要求的個數為止。但是和AGNES算法的區別是:取消了使用所有點或用中心點+距離來表示一個類
而是從每個類中抽取固定數量、分布較好的點作為此類的代表點,並將這些代表點乘以一個適當的收縮因子,使它們更加靠近類中心點。
代表點的收縮特性可以調整模型可以匹配那些非球形的場景,而且收縮因子的使用可以減少噪音對聚類的影響。
找幾個特殊的點來代替整個類別中的樣本
優缺點:能夠處理非球形分布的應用場景采用隨機抽樣和分區的方式可以提高算法的執行效率