聚類是一種運用普遍的探索性數據分析技術,直觀上講,聚類是將對象進行分組的一項任務,使類似的對象歸爲一類,不類似的對象歸爲不一樣類中。html
當聚類對象是圖像的時候,就是所謂的圖像聚類。git
更爲詳細的介紹,可參考文後的參考資料[1]。程序員
圖像聚類就是在給出的圖像集合中,根據圖像的內容,在無先驗知識的狀況下,將圖像按照類似度進行分類。使得分類後的圖像類內類似度高,類間類似度低。中國有句俗話叫作「物以類聚,人以羣分」,大概就是這個意思吧。github
前面講到聚類是將類似度高的對象聚到一類中,如何來衡量對象之間的類似度是個關鍵問題。算法
按照聚類的尺度,聚類方法能夠被分爲如下三種:數組
下面的部分主要介紹K-means
聚類方法。bash
K-means
算法是一種基於距離的聚類算法,也叫作K均值
或K平均
,也常常被稱爲勞埃德(Lloyd
)算法。是經過迭代的方式將數據集中的各個點劃分到距離它最近的簇內,距離指的是數據點到簇中心的距離。dom
K-means
算法的思想很簡單,對於給定的樣本集,按照樣本之間的距離大小,將樣本劃分爲K
個簇。將簇內的數據儘可能緊密的連在一塊兒,而讓簇間的距離儘可能的大。ide
Kmeans
步驟:函數
k
個簇中心座標k
個簇中心的距離,並將數據點劃分到最近的簇終止條件有:
- 再也不有從新的分配
- 達到最大迭代次數
- 全部類中心移動小於某個值
K-means
問題
貪心算法: 常常陷入局部最優解
K
的選取
對噪聲或離羣點比較敏感
沒法區分出哪些是噪聲或者離羣點,只能給每一個數據點都判斷出一個類別來,這樣會致使樣本質心偏移,致使誤判或者聚類緊密程度下降。
樣本點形狀對聚類的影響
K-means
算法對於凸性數據具備良好的效果,可以根據聚類來將數據分爲球狀類的簇,但對於非凸形狀的數據點就無能爲力了,好比環形數據等等。以下圖左邊是K-means
方法的聚類效果。
聚類中心的個數K
須要事先給定。K
值的選取直接影響最終的聚類效果。
選取方法:
elbow method
經過繪製K
和損失函數的關係圖,選擇拐點處的K
值。即便用多個值進行嘗試,取聚類指標最優或提高的轉折點。K
,屢次隨機初始化中心選經驗上最合適的。一般是根據經驗選取,由於實際操做中拐點不明顯,且效率過低,實際中不容許這樣作。
elbow method
也叫作「手肘法」,是利用偏差平方和(SSE)的變化趨勢來做爲選取K
值的指標。
其中,是第
個簇,
是
中的樣本點,
是
的質心,
是全部樣本的聚類偏差,表示聚類效果的好壞。
以下圖所示,當K
取值爲2~7時,對應的聚類結果,當K=5
時的效果最好。
K-means
選擇的初始點不一樣得到的最終分類結果也可能不一樣。在實際使用中,咱們並不知道待聚類的數據集中哪些是咱們關注的label
,人工事先指定質心是不現實的。
通常初始質心的選擇方法是:
Kmeans++
方式
K
個。距離是K-means
中衡量簇內樣本點類似度的指標。
K-means
中比較經常使用的距離度量方法是:
Python
中的sklearn
庫中提供了K-means
聚類的實現方法,咱們能夠直接調用。
對於圖像聚類來說,咱們須要提取表示圖像內容的特徵,
是
維的特徵向量。具備
個圖像,其特徵向量表示爲
,維度爲
。
示例:
from sklearn.cluster import KMeans
import numpy as np
# X表示一組圖像的特徵向量
X = np.array([[1, 2], [1, 4], [1, 0],
[4, 2], [4, 4], [4, 0]])
kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
kmeans.labels_
# array([0, 0, 0, 1, 1, 1], dtype=int32)
kmeans.predict([[0, 0], [4, 4]])
# array([0, 1], dtype=int32)
kmeans.cluster_centers_
# array([[ 1., 2.],
# [ 4., 2.]])
複製代碼
class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')
複製代碼
參數:
參數 | 含義 |
---|---|
n_clsuters |
int , 可選,默認值爲8 。聚類中心的個數,即聚類的類數 |
init |
{‘k-means++’ , 'random' 或一個ndarray},初始化質心的方法,默認是'k-means++' ,‘random’ 隨機從訓練數據中選初始質心,若是傳遞一個ndarray,應該行如(n_clusters, n_features) 並給出初始質心 |
n_init |
int ,默認10 ,用不一樣質心初始化運行算法的次數,最終解是在inertia意義下選出的最優結果 |
max_iter |
int ,默認300 ,執行一次K-means 算法的最大迭代次數 |
tol |
float 型,默認0.0001 |
precompute_distances |
{auto, True, False }預先計算距離值(更快,但佔用更多內存),對一組數據只運行較少次聚類結果時,不須要預選計算。 |
verbose |
int 型,默認0 ,是否打印中間過程,0是不打印 |
random_state |
int 型,RandomState 的實例或None ,可選,默認None 。若是是int ,random_state 是隨機數生成器使用的種子,若是是RandomState 實例,random_state 是隨機數生成器,若是是None ,隨機數生成器是由np.random 的RandomState 實例 |
n_jobs |
int 型,使用的計算力的數量,經過計算並行運行的每一個n_init來實現。若是是-1 ,則全部CPU所有使用,若是指定爲1 ,則不使用並行代碼,方便調試。該值小於-1,則使用 (n_cpus + 1 + n_jobs) . 對於n_jobs = -2 , 使用n_cpus-1 . |
algorithm |
可選值'auto', 'full','elkan' 。'full'是傳統的K-means算法,'elkan'是elkan K-means算法,默認值‘auto’會根據數據值是否稀疏,來決定如何選擇'full'和'elkan'。通常,數據稠密選‘elkan’,不然就是'full'。 |
主要屬性:
屬性 | 含義 |
---|---|
cluster_centers_ |
向量[n_clsuters, n_features],每一個簇中心的座標 |
Labels_ |
每一個數據的分類標籤,從0開始 |
inertia_ |
float 型,每一個數據點到其簇的質心的距離之和,用來評估簇的個數是否合適 |
1. fit()
對Kmeans肯定類別之後的數據集進行聚類.
定義:
def fit(self, X, y=None)
random_state = check_random_state(self.random_state)
X = self._check_fit_data(X)
self.cluster_centers_, self.labels_, self.inertia_, self.n_iter_ = \
k_means(
X, n_clusters=self.n_clusters, init=self.init,
n_init=self.n_init, max_iter=self.max_iter, verbose=self.verbose,
precompute_distances=self.precompute_distances,
tol=self.tol, random_state=random_state, copy_x=self.copy_x,
n_jobs=self.n_jobs, algorithm=self.algorithm,
return_n_iter=True)
return self
複製代碼
內部調用k_means
函數進行聚類,返回self
。
調用k_means()
函數,會返回self.cluster_centers_
,self.labels_
, self.inertia_
, self.n_iter_
。
self.cluster_centers_
:聚類中心,shape爲 (k, n_features)
self.labels_
:int
,聚類索引值,shape爲(n_samples,)
self.inertia_
:聚類失真值(訓練集中全部觀測到的距離的平方之和)self.n_iter_
:最佳結果對應的迭代次數,只有當 return_n_iter
設爲True
時返回。2. predict()
根據聚類結果,肯定所屬類別
def predict(self, X)
複製代碼
X
:{array, sparse matrix}
,shape是[n_samples, n_features]
返回值:labels
:array
, shape是[n_samples,]
。每一個樣例屬於聚類的類別索引。3. fit_predict
def fit_predict(self, X, y=None)
return self.fit(X).labels_
複製代碼
返回值:
labels
:array
, shape是[n_samples,]
。每一個樣例屬於聚類的類別索引值。計算聚類中,並預測每一個sample的聚類索引。
等效於,調用fit(X)
方法以後,調用predict(X)
函數。
注意:在此函數中,返回的是self.fit(X).labels_屬性。
4. transform
def transform(self, X)
複製代碼
將X轉化爲聚類-距離空間
返回值:
X_new
:array
, shape是[n_samples, k]
5. fit_transform
def fit_transform(self, X, y=None)
複製代碼
進行聚類運算,並將X
轉化到距離空間。
等效於,調用fit(X)
方法以後,調用transform(X)
函數,可是更爲有效。
重要,sklearn中的Kmeans方法沒法指定距離度量方法,默認使用歐式距離
K-means
默認使用的是歐式距離,這是算法設計之初的度量基礎。緣由是涉及平均值的計算。
scipy
庫中也實現了K-means
算法。
中心索引或聚類索引也被稱爲 「code」 ,code到中心的映射表被稱爲 「code book」.
使用kmeans
函數進行聚類,須要兩步來實現
kmeans
函數生成codebook
和失真值vq
函數將codebook
分配到每一個觀察數據上,並獲得每一個觀測數據到它最近中心點的距離。示例:
import scipy
from scipy.cluster.vq import kmeans, vq, whiten
import numpy as np
#生成待聚類的數據點,這裏生成了20個點,每一個點4維:
points=scipy.randn(20,4)
data=whiten(points) # 將原始數據作歸一化處理
#返回聚類中心的映射表和損失
codebook, variance = kmeans(data, 4)
# 使用vq函數根據聚類中心對全部數據進行分類,vq的輸出全部數據的label和距離
code, distance = vq(data, codebook)
# 結果
>>> codebook # (4,4)
array([[-1.227829 , -0.41256122, -0.1342359 , -0.98257834],
[ 1.01190005, -0.34999089, -0.13180372, 0.06394479],
[ 0.01156929, -0.39212056, 1.86893218, -0.34921357],
[ 0.21946277, 1.36809613, 0.87196001, 0.9213216 ]])
>>>variance
1.221658211170926
>>> code
array([2, 0, 0, 2, 0, 2, 1, 3, 1, 1, 3, 0, 1, 0, 1, 1, 3, 2, 3, 2],
dtype=int32)
>>>distance
array([1.32927696, 0.99594691, 1.38351644, 1.22323281, 1.12605626,
2.04444249, 0.55554746, 2.06947197, 1.44928466, 1.09481098,
1.60957745, 1.07210177, 1.3848659 , 0.6393925 , 0.69392457,
1.06200234, 1.09091552, 0.87726365, 0.76938663, 1.96214695])
複製代碼
kmeans函數定義:
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True)
複製代碼
參數:
obs
:ndarray
,MxN
數組,每行表示一個觀測矢量。特徵必須進過whiten
函數處理k_or_guess
:int
或者ndarray
,產生的中心點的個數,每一箇中心點分配一個code
,這也是質心在生成的code_book
矩陣中的行索引,經過從觀測矩陣中隨機選擇觀測值來選擇初始k中心。也能夠經過傳入一個kxN
的數組來指定初始k中心點。iter
:int
,可選值。運行k均值算法的次數,返回具備最低失真的code book
,若是爲k_or_guess
參數的數組指定了初始質心,則將忽略此參數,此參數不表明k均值算法的迭代次數。thresh
:float
,可選值。若是自上次k均值迭代以來失真的變化小於或等於閾值,則終止k均值算法。check_finite
:bool
,可選值,默認值:True
。是否檢查輸入矩陣僅包含有限數。禁用可能會提升性能,可是若是輸入中確實包含無窮大或NaN,則可能會致使問題(崩潰,終止)。返回:
codebook
:ndarray
,由k個質心組成的維度(k,N)
的數組distortion
:float
型,觀測值與生成的中心點之間的平均歐式距離(非平方)。請注意,在K-means
算法中失真的標準定義是平方距離總和。注意: 1. `kmeans`函數中,`iter`參數用來指定運行K均值算法的次數,而不是迭代次數。算法終止條件只能經過`thresh`參數來指定。 2. 距離度量使用的是平均歐式距離(非平方)
vq函數定義:
def vq(obs, code_book, check_finite=True)
複製代碼
將code book
中的每個code
分配給觀察值。在MXN
的數組中的每一個觀察矢量與code book
中的質心進行比較,併爲其分配最接近質心的code
.
obs
中的特徵應該具備單位方差,能夠經過將他們傳遞給whiten
函數來實現。code book
可使用K-means
算法或其餘編碼算法來建立。
參數:
obs
:MxN
數組,每一行表明一個觀測值。特徵必須通過whiten
函數處理。code_book
:ndarray
。一般使用k-means算法生成,每一行表示一個不一樣的code
,列表示code
的特徵值。check_finite
:bool
,可選值,默認是True
。是否檢查輸入數組中僅包含有限值。禁用可能會提升性能,但若是輸入內容確實包含無窮大或NaN,則可能會致使問題(崩潰,終止)。返回值:
code
: ndarray
,長度爲M的數組,用於保存每一個觀察數據的code book
。dist
: ndarray``,(M,)
每一個觀察數據到它最近code的失真值。該函數也是用來實現K-means
算法。該算法嘗試最小化觀測值和質心之間的歐幾里得距離,包括幾種初始化方法。
scipy.cluster.vq.kmeans2(data, k, iter=10, thresh=1e-05, minit='random', missing='warn', check_finite=True)
複製代碼
參數:
data
:ndarray
,(M,N)
的數組,包含M個具備N維的觀測數據。k
:int or ndarray
,聚類個數。若是minit
參數是matrix
,或者若是給定一個ndarray
,它被解釋爲初始聚類,以代替使用。iter
:int
,可選值,k-means
算法運行的迭代次數,注意,與kmeans
函數的iter
參數的含義不一樣。thresh
:float
,可選值,沒有使用minit
:str
,可選值,初始化方法。可選擇random
, points
,++
和matrix
。
random
:從高斯生成k個質心,均值和方差根據數據估算出points
:從數據中隨機選擇k個觀測值(行)做爲初始中心++
:根據kmeans++
方法選擇k個觀測值matrix
:將k參數解釋爲初始質心的(k,M)數組missing
:str
,可選值,用於解決空聚類的方法,可用方法有warn
和raise
。
warn
:給出警告並繼續raise
:引起ClusterError
並終止算法check_finite
:bool
,可選值,是否檢查輸入矩陣僅包含有限數,默認True
返回值:
centroid
:ndarray
:一個(k,N)的數組,表示k-means
方法最後一次迭代的中心點label
:ndarray
,每一個觀測值的代碼或索引值。label [i]是第i個觀測值最接近的質心的代碼或索引示例
import scipy
from scipy.cluster.vq import kmeans2, whiten
import numpy as np
#生成待聚類的數據點,這裏生成了20個點,每一個點4維:
points=scipy.randn(20,4)
data=whiten(points) # 將原始數據作歸一化處理
centroid, label = kmeans2(data, 5)
# 結果
>>> centroid
array([[ 0.52132816, 0.97577703, -0.30863464, -1.30546523],
[-0.27344139, -0.81129939, -0.59560322, 0.47788319],
[ 1.99658961, -0.10701021, 1.09921144, 0.51397034],
[-0.37598454, 1.72180727, -0.18127439, 0.58114466],
[ 0.25895367, -0.01881385, 1.25681737, 0.03119893]])
>>> label
array([1, 0, 3, 0, 1, 1, 2, 4, 0, 1, 1, 0, 4, 4, 0, 3, 1, 4, 3, 2],
dtype=int32)
複製代碼
[1]各種聚類(clustering)算法初探 - 鄭瀚Andrew.Hann - 博客園
[2]特徵提取方法:聚類之Kmeans - Jack_Kuo的博客 - CSDN博客
[3]sklearn.cluster.KMeans — scikit-learn 0.17 文檔
[4]K-means clustering and vector quantization (scipy.cluster.vq) — SciPy v1.3.1 Reference Guide