1. 程式人生 > >機器學習5-無監督學習與聚類

機器學習5-無監督學習與聚類

目錄

聚類

分類 vs. 聚類
class cluster
有監督 無監督
樣本相似性:歐氏距離
歐幾里得
《幾何原理》
不同維度的距離求解:
P(x1) - Q(x2): |x1-x2| = sqrt((x1-x2)2)
P(x1,y1) - Q(x2,y2): sqrt((x1-x2)2

+(y1-y2)2)
P(x1,y1,z1) - Q(x2,y2,z2):sqrt((x1-x2)2+ (y1-y2)2+(z1-z2)2)
用兩個樣本對應特徵值之差的平方和之平方根,即歐氏距離,來表示這兩個樣本的相似性。

K均值演算法

聚類中心:任意一個聚類成員與該聚類中心的距離一定小於該成員與其他聚類中心的距離
幾何中心:聚類中所有成員對應特徵值的算數平均數表示的虛擬樣本-抽象性。
理想聚類:聚類中心與幾何中心重合。
在總樣本空間中,隨機選擇K個樣本作為初始聚類中心,計算所有樣本距離每個聚類中心的歐氏距離,離哪個中心斤就隸屬於該中心所表示的類別,這樣就完成了一次聚類劃分,針對所得到的每個聚類,計算其樣本集的幾何中心,如果幾何中心與計算中心不重合,以幾何中心作為新的聚類中心重新計算每個樣本與其劃分所依據的聚類中心重合或足夠接近為止。
問題:

  • 聚類數K需要事先知道。
    通過效能指標優選最好的K
  • 初始聚類中心的選擇可能會影響最終的聚類劃分結果。
    以最大間距原則選擇初始的聚類中心
    示例:
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp

x = []
with open(r'C:\Users\Cs\Desktop\機器學習\ML\data\multiple3.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr)
for substr in line.split(',')] x.append(data) x = np.array(x) # K均值聚類器,n_clusters聚類數(核心數) model = sc.KMeans(n_clusters=4) model.fit(x) centers = model.cluster_centers_ l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005 b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005 grid_x = np.meshgrid(np.arange(l, r, h), np.arange(b, t, v)) flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()] flat_y = model.predict(flat_x) grid_y = flat_y.reshape(grid_x[0].shape) pred_y = model.predict(x) mp.figure('K-Means Cluster', facecolor='lightgray') mp.title('K-Means Cluster', fontsize=20) mp.xlabel('x', fontsize=14) mp.ylabel('y', fontsize=14) mp.tick_params(labelsize=10) mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray') mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80) mp.scatter(centers[:, 0], centers[:, 1], marker='+', c='gold', s=1000, linewidth=1) mp.show()

圖片量化

通過聚類的方法,將圖片中的不同顏色(或者灰度的不同亮度)進行聚類,得到單色圖。

import numpy as np
import cv2
import sklearn.cluster as sc
import matplotlib.pyplot as mp

image1 = cv2.imread(r'C:\Users\Cs\Desktop\3.jpg', cv2.IMREAD_GRAYSCALE)
model=sc.KMeans(2)
# 轉換成一維
model.fit(image1.reshape((-1,1)))
y=model.labels_
print("y:",y)

centers=model.cluster_centers_
print("centers:",centers)
# 通過網篩得到圖片矩陣
x=centers[y].reshape(image1.shape)
mp.imshow(x)
mp.show()

均值漂移演算法

首先假定樣本空間中的每個聚類均服從某種已知的概率分佈規則,然後用不同的概率密度函式擬合樣本中的統計直方圖,不斷移動密度函式的中心(均值)的位置,直到獲得最佳擬合效果為止。這些概率密度函式的峰值點就是聚類的中心,再根據每個樣本距離各個中心的距離,選擇最近聚類中心所屬的類別作為該樣本的類別。
1)聚類數不必事先已知,演算法會自動識別出統計直方圖的中心數量。
2)聚類中心不依據於最初假定,聚類劃分的結果相對穩定。
3)樣本空間應該服從某種概率分佈規則,否則演算法的準確性會大打折扣。
聚類中心:
k均值演算法的聚類中心:幾何中心----------------\基於中心
均值漂移演算法的聚類中心:隨機分佈中心------/ 的預測

程式碼:

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open('../../data/multiple3.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr
                in line.split(',')]
        x.append(data)
x = np.array(x)
# 量化頻寬,決定每次調整概率密度函式的步進量
bw = sc.estimate_bandwidth(x, n_samples=len(x),
                           quantile=0.1)
# 均值漂移聚類器,bin_seeding:如果為真,初始化點不是所有點,可以加快迭代速度,初始化位置更少
model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
model.fit(x)
centers = model.cluster_centers_
...

凝聚層次演算法

首先假定每個樣本都是一個獨立的聚類,如果統計出來的聚類數大於期望的聚類數,則從每個樣本出發尋找離自己最近的另一個樣本,與之聚集,形成更大的聚類,同時令總聚類數減少,不斷重複以上過程,直到統計出來的聚類數達到期望值為止。
1)聚類數k必須事先已知。
藉助某些評估指標,優選最好的聚類數。
2)沒有聚類中心的概念,因此只能在訓練集中劃分聚類,但不能對訓練集以外的未知樣本確定其聚類歸屬。
3)在確定被凝聚的樣本時,除了以距離作為條件以外,還可以根據連續性來確定被聚集的樣本。

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open('../../data/multiple3.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr
                in line.split(',')]
        x.append(data)
x = np.array(x)
# 凝聚層次聚類器
model = sc.AgglomerativeClustering(n_clusters=4)
pred_y = model.fit_predict(x)
mp.figure('Agglomerative Cluster',
          facecolor='lightgray')
mp.title('Agglomerative Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg',
           s=80)
mp.show()

基於距離的凝聚:塊狀凝聚
基於線性(連續性)的凝聚:線狀凝聚

凝聚層次演算法的線性凝聚方式

凝聚成此演算法可以線性凝聚和塊狀凝聚。具體使用如下:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import sklearn.neighbors as nb
import matplotlib.pyplot as mp

n_samples = 500
t = 2.5 * np.pi * (1 + 2 * np.random.rand(n_samples, 1))
x = 0.05 * t * np.cos(t)
y = 0.05 * t * np.sin(t)
n = 0.05 * np.random.rand(n_samples, 2)
x = np.hstack((x, y)) + n
# 無連續性的凝聚層次聚類器
model_nonc = sc.AgglomerativeClustering(linkage='average', n_clusters=3)
pred_y_nonc = model_nonc.fit_predict(x)
# 近鄰篩選器
conn = nb.kneighbors_graph(x, 10, include_self=False)
# 有連續性的凝聚層次聚類器
model_conn = sc.AgglomerativeClustering(linkage='average', n_clusters=3,
                                        connectivity=conn)
pred_y_conn = model_conn.fit_predict(x)
mp.figure('Nonconnectivity',
          facecolor='lightgray')
mp.title('Nonconnectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.axis('equal')
mp.scatter(x[:, 0], x[:, 1], c=pred_y_nonc, cmap='brg', alpha=0.5, s=60)
mp.figure('Connectivity', facecolor='lightgray')
mp.title('Connectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.axis('equal')
mp.scatter(x[:, 0], x[:, 1], c=pred_y_conn, cmap='brg', alpha=0.5, s=60)
mp.show()

在這裡插入圖片描述

輪廓係數

好的聚類:內密外疏,同一個聚類內部的樣本要足夠密集,不同聚類之間樣本要足夠疏遠。
電視機
皮夾克
電冰箱
羽絨服
好!
A : 電視機,電冰箱
B : 皮夾克,羽絨服
差!
A : 電視機,羽絨服
B : 電冰箱,皮夾克
通過輪廓係數表示聚類內密外輸的程度,即聚類的性別。
一個樣本的輪廓係數:s=(b-a)/max(a,b)
將整個樣本空間中所有樣本的輪廓係數取算數平均值,作為聚類劃分的效能指標s。
  -1 <----- 0 -----> 1 
最差    聚類重疊     最好
sm.silhouette_score(輸入集, 輸出集, sample_size=樣本數, metric=距離演算法)->平均輪廓係數
    距離演算法:euclidean,歐幾里得距離
    輸出值通過訓練的model.predict(x)得到
import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x = []
with open(r'C:\Users\Cs\Desktop\機器學習\ML\data\multiple3.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr
                in line.split(',')]
        x.append(data)
x = np.array(x)
# K均值聚類器
model = sc.KMeans(n_clusters=4)
model.fit(x)
centers = model.cluster_centers_
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
grid_x = np.meshgrid(np.arange(l, r, h),
                     np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()]
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)
pred_y = model.predict(x)
# 列印平均輪廓係數
print(sm.silhouette_score(
    x, pred_y, sample_size=len(x),
    metric='euclidean'))
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y,
              cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg',
           s=80)
mp.scatter(centers[:, 0], centers[:, 1], marker='+',
           c='gold', s=1000, linewidth=1)
mp.show()

DBSCAN(帶噪聲的基於密度的聚類)演算法

DBSCAN(帶噪聲的基於密度的聚類)演算法
核心思想:朋友的朋友也是朋友
從樣本空間中任意選擇一個樣本,以事先給定的半徑做圓,凡被該圓圈中的樣本都視為與該樣本處於相同的聚類,以這些被圈中的樣本為圓心繼續做圓,重複以上過程,不斷擴大被圈中樣本的規模,直到再也沒有新的樣本加入為止,至此即得到一個聚類。於剩餘樣本中,重複以上過程,直到耗盡樣本空間中的所有樣本為止。
1)事先給定的半徑會影響最後的聚類效果,可以藉助輪廓係數選擇較優的方案。
2)根據聚類的形成過程,把樣本細分為以下三類:
外周樣本:被其它樣本聚集到某個聚類中,但無法再引入新樣本的樣本。
孤立樣本:聚類中的樣本數低於所設定的下限,則不稱其為聚類,反之稱其為孤立樣本。
核心樣本:除了外周樣本和孤立樣本以外的樣本。
程式碼:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as mp

x = []
with open(r'C:\Users\Cs\Desktop\機器學習\ML\data\perf.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr
                in line.split(',')]
        x.append(data)
x = np.array(x)
# epsilons:
epsilons, scores, models = np.linspace(0.3, 1.2, 10), [], []
for epsilon in epsilons:
    # DBSCAN聚類器
    model = sc.DBSCAN(eps=epsilon, min_samples=5)
    model.fit(x)
    # 獲取當前model的輪廓係數
    score = sm.silhouette_score(x, model.labels_, sample_size=len(x), metric='euclidean')
    scores.append(score)
    models.append(model)
scores = np.array(scores)
best_index = scores.argmax()
# 得到最佳半徑係數
best_epsilon = epsilons[best_index]
print(best_epsilon)
# 得到最佳輪廓係數
best_score = scores[best_index]
print(best_score)
# 得到最佳模型
best_model = models[best_index]
# 得到聚類結果,注意fit_predict方法,這裡居然沒有predict方法
pred_y = best_model.fit_predict(x)

core_mask = np.zeros(len(x), dtype=bool)
# DBSCAN屬性:
#core_sample_indices_: array, shape = [n_core_samples]:核心點標籤。
# components_: array, shape = [n_core_samples, n_features]:通過培訓找到的每個核心樣本的副本。
# labels_: array, shape = [n_samples]:將資料集中每個點的標籤聚類到fit()中。噪聲樣本被標記為-1。
#指數核心樣本的下標
core_mask[best_model.core_sample_indices_] = True
print("core_sample_indices_:",best_model.core_sample_indices_)
print("coremask:",core_mask)
# 噪聲點
offset_mask = best_model.labels_ == -1
#邊緣點
periphery_mask = ~(core_mask | offset_mask)

mp.figure('DBSCAN Cluster', facecolor='lightgray')
mp.title('DBSCAN Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
labels = set(pred_y)
cs = mp.get_cmap('brg', len(labels))(
    range(len(labels)))
mp.scatter(x[core_mask][:, 0], x[core_mask][:, 1],
           c=cs[pred_y[core_mask]], s=80,
           label='Core')
mp.scatter(x[periphery_mask][:, 0], x[periphery_mask][:, 1],
           edgecolor=cs[pred_y[periphery_mask]],
           facecolor='none', s=80, label='Periphery')
mp.scatter(x[offset_mask][:, 0], x[offset_mask][:, 1