1、無監督學習聚類:
按照相似度對數據進行聚簇(cluster)劃分,N個樣本映射到K個簇中,每個簇至少有一個樣本,一個樣本只能屬於一個簇,先給定一個初始劃分,迭代改變樣本和簇的關係,聚類的副產品可以做異常值檢測
2、相似度指標有:
多維空間向量點之間的距離(閔可夫斯基距離公式):
當p爲2時即歐式距離(二維空間距離公式):
當p爲1時即曼哈頓距離(Block Distance)
三維空間距離公式:
當p趨近於無窮大時即切比雪夫距離(由於維度無窮多,所有維度差值最大的維度距離差可以近似距離)
Jaccard相關係數(Jaccard similarity coefficient)比較有限樣本集之間的相似度:
餘弦相似度:餘弦值區間爲[-1,1],餘弦值接近-1相似度越小接近0向量正交接近1相似度越大,一般用於文檔相似度聚類
Pearson相關係數(線性相關性):
兩個變量之間的協方差和標準差的商,Xi與Yi爲0時即爲餘弦相似度公式
3、K-Means聚類平均數算法:
選擇K個初始簇中心(隨機或者先驗知識即經驗),迭代計算樣本與每個聚類中心的距離和所屬聚類的樣本均值即簇中心點直到簇中心點不發生變化認爲模型收斂
劃分:
4、K-Mediods聚類中位數算法:
對K-Means聚類算法的改進以中位數作爲簇中心點
5、二分K-Means算法:
兩個簇樣本數量少簇中心近損失函數MSE小合併爲一個簇,簇中心離其他簇中心遠樣本數量大損失函數MSE大分爲多個簇
6、K-Means++:
對K-Means聚類算法的改進,初始化中心點均有隨機,使用肘部法找到最合適的K即簇的數量
K均值假設符合高斯混合分佈,高斯混合分佈不是線性迴歸凹函數,有多個極小值,可以用淬火法或遺傳算法計算全局最優解,K-Means算法是根據樣本到簇中心點的距離進行聚類所以算法更適合對近似圓形規則的樣本進行聚類。
# !/usr/bin/python
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
from sklearn.cluster import KMeans # 引入K-Means模塊
# 引入小批量K-Means模塊(計算簇中心不使用所有樣本隨機部分樣本求簇中心,計算速度快,數據量大可以使用)
from sklearn.cluster import MiniBatchKMeans
def expand(a, b):
d = (b - a) * 0.1
return a-d, b+d
if __name__ == "__main__":
# 創建 400 個樣本
N = 400
# 4 個類別
centers = 4
# 生成N個樣本n_features個維度centers個簇中心的聚類模擬數據
# n_features = 2 ,即 x1 , x2 ,兩個維度特徵
data, y = ds.make_blobs(N, n_features=2, centers=centers, random_state=2)
# 生成樣本數據方差爲cluster_std(即數據分散程度)的聚類模擬數據,方差小的數據要密一些
data2, y2 = ds.make_blobs(N, n_features=2, centers=centers, cluster_std=(1, 2.5, 0.5, 2), random_state=2)
# 獲取簇樣本數量不一致的聚類模擬數據
data3 = np.vstack((data[y == 0][:], data[y == 1][:50], data[y == 2][:20], data[y == 3][:5]))
y3 = np.array([0] * 100 + [1] * 50 + [2] * 20 + [3] * 5)
# 獲取簇中心即K爲n_clusters初始化使用init的k-means對象
cls = KMeans(n_clusters=4, init='k-means++')
# 訓練模型並獲取預測值
y_hat = cls.fit_predict(data)
y2_hat = cls.fit_predict(data2)
y3_hat = cls.fit_predict(data3)
m = np.array(((1, 1), (1, 3)))
# 對矩陣進行旋轉
data_r = data.dot(m)
y_r_hat = cls.fit_predict(data_r)
matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
cm = matplotlib.colors.ListedColormap(list('rgbm'))
plt.figure(figsize=(9, 10), facecolor='w')
plt.subplot(421)
plt.title(u'原始數據')
# 繪製散點圖
plt.scatter(data[:, 0], data[:, 1], c=y, s=30, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data, axis=0)
x1_max, x2_max = np.max(data, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(422)
plt.title(u'KMeans++聚類')
plt.scatter(data[:, 0], data[:, 1], c=y_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(423)
plt.title(u'旋轉後數據')
plt.scatter(data_r[:, 0], data_r[:, 1], c=y, s=30, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data_r, axis=0)
x1_max, x2_max = np.max(data_r, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(424)
plt.title(u'旋轉後KMeans++聚類')
plt.scatter(data_r[:, 0], data_r[:, 1], c=y_r_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(425)
plt.title(u'方差不相等數據')
plt.scatter(data2[:, 0], data2[:, 1], c=y2, s=30, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data2, axis=0)
x1_max, x2_max = np.max(data2, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(426)
plt.title(u'方差不相等KMeans++聚類')
plt.scatter(data2[:, 0], data2[:, 1], c=y2_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(427)
plt.title(u'數量不相等數據')
plt.scatter(data3[:, 0], data3[:, 1], s=30, c=y3, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data3, axis=0)
x1_max, x2_max = np.max(data3, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.subplot(428)
plt.title(u'數量不相等KMeans++聚類')
plt.scatter(data3[:, 0], data3[:, 1], c=y3_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.tight_layout(2, rect=(0, 0, 1, 0.97))
plt.suptitle(u'數據分佈對KMeans聚類的影響', fontsize=18)
# https://github.com/matplotlib/matplotlib/issues/829
# plt.subplots_adjust(top=0.92)
plt.show()
# plt.savefig('cluster_kmeans')
7、Canopy聚類算法:
簇中心點分佈均勻、K值不需要指定、樣本可以屬於多個簇類和一次迭代,一般用於在K-Means算法之前獲取先驗知識即K的個數和簇中心分佈位置
Canopy算法流程圖:
Canopy算法首先選擇兩個距離閾值:T1和T2,其中T1 > T2
(1)原始狀態下的數據還沒有分類,所以從集合中取出一點P,將P作爲第一個類,我們也將類稱爲Canopy。
(2)繼續從集合中取點,比如P,計算P到已經產生的所有Canopy的距離,如果到某個Canopy的距離小於T1,則將P加入到該Canopy;如果P到所有Canopy中心的距離都大於T1,則將P作爲一個新Canopy,如下圖中的Q就是一個新的Canopy。
(3)如果P到該Canopy距離小於T2,則表示P和該Canopy已經足夠近,此時將P從從集合中刪除,避免重複加入到其他Canopy。
(4)對集合中的點繼續執行上述操作直到集合爲空,算法結束,聚類完成。
8、聚類算法評估指標:
Given Label:
同一性(Homogeneity):一個簇中只包含一個類別樣本
完整性(Completeness):同類別樣本歸屬到同一個簇中
同一性與完整性TradeOff互相制約,兩者加權平均的評估指標V-Measure:
# !/usr/bin/python
# -*- coding:utf-8 -*-
from sklearn import metrics # 引入評估模塊
"""
同一性(Homogeneity):一個簇中只包含一個類別樣本
完整性(Completeness):同類別樣本歸屬到同一個簇中
"""
if __name__ == "__main__":
y = [0, 0, 0, 1, 1, 1]
# y_hat 是聚類的結果,有 0,1,2 三個類別,三個類別裏分別有兩個點
y_hat = [0, 0, 1, 1, 2, 2]
h = metrics.homogeneity_score(y, y_hat) # 獲取同一性評估指標
c = metrics.completeness_score(y, y_hat) #獲取完整性評估指標
print(u'同一性(Homogeneity):', h)
print(u'完整性(Completeness):', c)
# 這是聚類算法的評估指標,此時參數β取1
# 同一性與完整性兩者加權的評估指標V-Measure: Vβ = [(1+β)*h*c] / [β*h + c]
v2 = 2 * c * h / (c + h)
# v 直接從包裏獲取公式,結果與 v2 相同
v = metrics.v_measure_score(y, y_hat) # 獲取V-Measure評估指標
print(u'V-Measure:', v2, v)
# 與上面的算法一致,y_hat與上面取值不同
# 允許不同值
y = [0, 0, 0, 1, 1, 1]
y_hat = [0, 0, 1, 3, 3, 3]
h = metrics.homogeneity_score(y, y_hat)
c = metrics.completeness_score(y, y_hat)
v = metrics.v_measure_score(y, y_hat)
print(u'同一性(Homogeneity):', h)
print(u'完整性(Completeness):', c)
print(u'V-Measure:', v)
# 與上面的算法一致,y_hat與上面取值不同
# 允許不同值
y = [0, 0, 0, 1, 1, 1]
y_hat = [1, 1, 1, 0, 0, 0]
h = metrics.homogeneity_score(y, y_hat)
c = metrics.completeness_score(y, y_hat)
v = metrics.v_measure_score(y, y_hat)
print(u'同一性(Homogeneity):', h)
print(u'完整性(Completeness):', c)
print(u'V-Measure:', v)
# 與上面的算法一致,y_hat與上面取值不同
y = [0, 0, 1, 1]
y_hat = [0, 1, 0, 1]
ari = metrics.adjusted_rand_score(y, y_hat)
print(ari)
y = [0, 0, 0, 1, 1, 1]
y_hat = [0, 0, 1, 1, 2, 2]
ari = metrics.adjusted_rand_score(y, y_hat)
print(ari)
9、輪廓係數:
度量樣本與同簇其他樣本的相似性:同簇中每個樣本到同簇內其他樣本的平均距離
度量樣本與其他簇的不相似性:簇中每個樣本到不同簇內所有樣本的平均距離,與不同簇之間的最小平均距離
樣本聚類合理Si接近1應該分到其他簇中Si接近-1在簇分界上Si接近0
10、層次聚類
(適用於有層級關係的數據樣本):
分裂的層次聚類(DIANA):將原始數據集不斷的迭代分裂,計算每個子數據集中的相似性,根據相似性繼續迭代分裂,將數據集分裂成多個類別
凝聚的層次聚類(AGNES):將數據集的每個樣本不斷迭代向上聚類後按層聚類直到聚成一個數據集
11、密度聚類:
統計樣本週邊的密度,將密度給定一個閾值,不斷的將樣本添加到最近的簇中,可以進行對不規則數據樣本的聚類即不類似圓形(適合K-Means算法)的數據,密度聚類計算複雜度大,可以通過索引來降低計算時間降低查找速度
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)密度聚類算法:
給定對象半徑內的區域爲對象領域,區域內樣本個數超過閾值的對象爲核心對象,核心對象到區域內的其他樣本爲核心密度可達,其他樣本迭代規劃對象半徑區域,核心密度可達通過樣本區域傳遞到其他樣本爲密度可達,一個樣本密度可達的兩個樣本成爲密度相連,最大密度相連構成的集合爲簇,一個樣本既不是核心對象也不能被別的樣本密度可達爲噪聲。
DBSCAN密度聚類算法的步驟:
DBSCAN的主要優點有:
1) 可以對任意形狀的稠密數據集進行聚類,相對的,K-Means之類的聚類算法一般只適用於凸數據集。
2) 可以在聚類的同時發現異常點,對數據集中的異常點不敏感。
3) 聚類結果沒有偏倚,相對的,K-Means之類的聚類算法初始值對聚類結果有很大影響。
DBSCAN的主要缺點有:
1)如果樣本集的密度不均勻、聚類間距差相差很大時,聚類質量較差,這時用DBSCAN聚類一般不適合。
2) 如果樣本集較大時,聚類收斂時間較長,此時可以對搜索最近鄰時建立的KD樹或者球樹進行規模限制來改進。
3) 調參相對於傳統的K-Means之類的聚類算法稍複雜,主要需要對距離閾值ϵ,鄰域樣本數閾值MinPts聯合調參,不同的參數組合對最後的聚類效果有較大影響。
# !/usr/bin/python
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
from sklearn.cluster import DBSCAN # 導入密度聚類模塊
from sklearn.preprocessing import StandardScaler
def expand(a, b):
d = (b - a) * 0.1
return a-d, b+d
if __name__ == "__main__":
N = 1000 # N 爲樣本點的個數
centers = [[1, 2], [-1, -1], [1, -1], [-1, 1]] # centers 爲 4 箇中心點
# n_features=2 ,二維 x1 ,x2 ,cluster_std=[0.5, 0.25, 0.7, 0.5] 爲 4 個正態分佈的方差,random_state=0 給定數據輸入的方式
data, y = ds.make_blobs(N, n_features=2, centers=centers, cluster_std=[0.5, 0.25, 0.7, 0.5], random_state=0)
data = StandardScaler().fit_transform(data) # StandardScaler() 做歸一化(對數據進行相應的算法)用的
# 數據的參數:(epsilon, min_sample),設置超參數
params = ((0.2, 5), (0.2, 10), (0.2, 15), (0.3, 5), (0.3, 10), (0.3, 15))
matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(12, 8), facecolor='w')
plt.suptitle(u'DBSCAN聚類', fontsize=20)
for i in range(6): # 遍歷超參數
eps, min_samples = params[i]
model = DBSCAN(eps=eps, min_samples=min_samples) # 獲取DBSCAN聚類模型
model.fit(data)
y_hat = model.labels_
core_indices = np.zeros_like(y_hat, dtype=bool)
core_indices[model.core_sample_indices_] = True
y_unique = np.unique(y_hat)
n_clusters = y_unique.size - (1 if -1 in y_hat else 0)
print(y_unique, '聚類簇的個數爲:', n_clusters)
plt.subplot(2, 3, i+1)
clrs = plt.cm.Spectral(np.linspace(0, 0.8, y_unique.size))
print(clrs)
for k, clr in zip(y_unique, clrs):
cur = (y_hat == k)
if k == -1:
plt.scatter(data[cur, 0], data[cur, 1], s=20, c='k')
continue
plt.scatter(data[cur, 0], data[cur, 1], s=30, c=clr, edgecolors='k')
plt.scatter(data[cur & core_indices][:, 0], data[cur & core_indices][:, 1], s=60, c=clr, marker='o', edgecolors='k')
x1_min, x2_min = np.min(data, axis=0)
x1_max, x2_max = np.max(data, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.title(u'epsilon = %.1f m = %d,聚類數目:%d' % (eps, min_samples, n_clusters), fontsize=16)
plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()
12、譜和譜聚類:
譜:Y=A*X,矩陣X乘以A等於對矩陣X做了空間線性變換,那麼Y=map(X),A是map這個線性算子,它的所有特徵值的全體,稱之爲方陣的譜,方陣的譜半徑爲最大的特徵值
譜聚類是一種基於圖論的聚類方法,通過對樣本數據的拉普拉斯矩陣的特徵向量進行聚類,以達到對樣本數據進行聚類的目的
譜聚類解決區域重疊問題,密度聚類與K-Means聚類不適合對區域重疊的數據進行聚類
樣本數據集可以構建成全連接圖,並且兩兩樣本之間可以求相似度,兩兩樣本之間構建鄰接矩陣來表示圖,鄰接矩陣W上面的值是用高斯相似度計算
W矩陣按行或列加和得對角陣D
L=D-W,L矩陣爲Laplace矩陣
向量v與變換A滿足Av=λv,向量v是變換A的一個特徵向量,λ是相應的特徵值
L矩陣是N*N的,N是樣本個數,實數形成的對數矩陣,求特徵值和特徵向量
所有特徵向量根據排序默認從小到大,逆序之後獲取特徵向量最大的幾個列向量實現降維,用這些列向量表示新的對應每個樣本的重要特徵,然後用K-Means聚類算法對樣本進行聚類即Laplace矩陣做主成分分析PCA(主成分分析技術,又稱主分量分析,利用降維的思想將多指標轉化爲少數幾個綜合指標)進行做K均值聚類
算法描述
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
from sklearn.cluster import spectral_clustering
from sklearn.metrics import euclidean_distances
def expand(a, b):
d = (b - a) * 0.1
return a-d, b+d
if __name__ == "__main__":
matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
t = np.arange(0, 2*np.pi, 0.1)
data1 = np.vstack((np.cos(t), np.sin(t))).T
data2 = np.vstack((2*np.cos(t), 2*np.sin(t))).T
data3 = np.vstack((3*np.cos(t), 3*np.sin(t))).T
data = np.vstack((data1, data2, data3))
n_clusters = 3
m = euclidean_distances(data, squared=True)
sigma = np.median(m)
plt.figure(figsize=(12, 8), facecolor='w')
plt.suptitle(u'譜聚類', fontsize=20)
clrs = plt.cm.Spectral(np.linspace(0, 0.8, n_clusters))
for i, s in enumerate(np.logspace(-2, 0, 6)):
print(s)
af = np.exp(-m ** 2 / (s ** 2)) + 1e-6
y_hat = spectral_clustering(af, n_clusters=n_clusters, assign_labels='kmeans', random_state=1)
plt.subplot(2, 3, i+1)
for k, clr in enumerate(clrs):
cur = (y_hat == k)
plt.scatter(data[cur, 0], data[cur, 1], s=40, c=clr, edgecolors='k')
x1_min, x2_min = np.min(data, axis=0)
x1_max, x2_max = np.max(data, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.title(u'sigma = %.2f' % s, fontsize=16)
plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()