1. 程式人生 > 其它 >K均值聚類

K均值聚類

2022年05月26日15:13:27
K均值聚類
預測的是一個離散值時,做的工作就是“分類”。

預測的是一個連續值時,做的工作就是“迴歸”。

機器學習模型還可以將訓練集中的資料劃分為若干個組,每個組被稱為一個“簇(cluster)”。這種學習方式被稱為“聚類(clusting)”,它的重要特點是在學習過程中不需要用標籤對訓練樣本進行標註。也就是說,學習過程能夠根據現有訓練集自動完成分類(聚類)。

根據訓練資料是否有標籤,可以將學習劃分為監督學習和無監督學習。

K近鄰、支援向量機都是監督學習,提供有標籤的資料給演算法學習,然後對資料分類

聚類是無監督學習,事先並不知道分類標籤是什麼,直接對資料分類。

聚類能夠將具有相似屬性的物件劃分到同一個集合(簇)中。

聚類方法能夠應用於所有物件,簇內的物件越相似,聚類演算法的效果越好。

K均值聚類的基本步驟
K均值聚類是一種將輸入資料劃分為k個簇的簡單的聚類演算法,該演算法不斷提取當前分類的中心點(也稱為質心或重心),並最終在分類穩定時完成聚類。

從本質上說,K均值聚類是一種迭代演算法。

在實際處理過程中需要進行多輪的迭代,直到分組穩定不再發生變化,即可認為分組完成。

K均值聚類演算法的基本步驟如下:

隨機選取k個點作為分類的中心點。
將每個資料點放到距離它最近的中心點所在的類中。
重新計算各個分類的資料點的平均值,將該平均值作為新的分類中心點。
重複步驟2和步驟3,直到分類穩定。
可以是隨機選取k個點作為分類的中心點,也可以是隨機生成k個並不存在於原始資料中的資料點作為分類中心點。

距離最近: 要進行某種形式的距離計算。(在具體實現時,可以根據需要採用不同形式的距離度量方法。)

K均值聚類模組
OpenCV提供了函式cv2.kmeans()來實現K均值聚類。

該函式的語法格式為:

retval, bestLabels, centers=cv2.kmeans(data, K, bestLabels, criteria, attempts,
flags)
data:輸入的待處理資料集合,應該是np.float32型別,每個特徵放在單獨的一列中。
K:要分出的簇的個數,即分類的數目,最常見的是K=2,表示二分類。
bestLabels:表示計算之後各個資料點的最終分類標籤(索引)。實際呼叫時,引數bestLabels的值設定為None。
criteria:演算法迭代的終止條件。當達到最大迴圈數目或者指定的精度閾值時,演算法停止繼續分類迭代計算。該引數由3個子引數構成,分別為type、max_iter和eps。
type表示終止的型別,可以是三種情況
cv2.TERM_CRITERIA_EPS:精度滿足eps時,停止迭代。
cv2.TERM_CRITERIA_MAX_ITER:迭代次數超過閾值max_iter時,停止迭代。
cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER:上述兩個條件中的任意一個滿足時,停止迭代。
max_iter:最大迭代次數。
eps:精確度的閾值。
attempts:在具體實現時,為了獲得最佳分類效果,可能需要使用不同的初始分類值進行多次嘗試。指定attempts的值,可以讓演算法使用不同的初始值進行多次(attempts次)嘗試。
flags:表示選擇初始中心點的方法,主要有以下3種。
cv2.KMEANS_RANDOM_CENTERS:隨機選取中心點。
cv2.KMEANS_PP_CENTERS:基於中心化演算法選取中心點。
cv2.KMEANS_USE_INITIAL_LABELS:使用使用者輸入的資料作為第一次分類中心點;如果演算法需要嘗試多次(attempts 值大於1時),後續嘗試都是使用隨機值或者半隨機值作為第一次分類中心點。
retval:距離值(也稱密度值或緊密度),返回 每個點到相應中心點距離的平方和(是一個數)。
bestLabels:各個資料點的最終分類標籤(索引)。
centers:每個分類的中心點資料。
簡單例子
例1:

隨機生成一組資料,使用函式cv2.kmeans()對其分類。

一組資料在[0,50]區間

另一組資料在[200,250]區間

使用函式cv2.kmeans()對它們分類。

主要步驟如下:

資料預處理

使用隨機函式隨機生成兩組資料,並將它們轉換為函式cv2.kmeans()可以處理的格式。

設定引數

設定函式cv2.kmeans()的引數形式。將引數criteria的值設定為“(cv2.TERM_CRITERIA_EPS+ cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)”,在達到一定次數或者滿足一定精度時終止迭代。

呼叫函式cv2.kmeans()

呼叫函式cv2.kmeans(),獲取返回值,用於後續步驟的操作。

確定分類

根據函式cv2.kmeans()返回的標籤(“0”和“1”),將原始資料分為兩組

顯示結果

繪製經過分類的資料及中心點,觀察分類結果。

完整程式:

import numpy as np
import cv2
from matplotlib import pyplot as plt
# 隨機生成兩組陣列
# 生成60個值在[0,50]內的資料
num1 = np.random.randint(0,50,60)
# 生成60個值在[200,250]內的資料
num2 = np.random.randint(200,250,60)
# 組合資料為num
num = np.hstack((num1, num2))
# 使用reshape函式將其轉換為(120,1)
num = num.reshape((120,1)) #每個資料為1列
# 轉換為float32型別
num = np.float32(num)
# 呼叫kmeans模組
# 設定引數criteria的值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# 設定引數flags的值
flags = cv2.KMEANS_RANDOM_CENTERS
# 呼叫函式kmeans
retval, bestLabels, centers = cv2.kmeans(num,2, None, criteria,10, flags)

# 列印返回值
print(retval)
print(bestLabels)
print(centers)

# 獲取分類結果
n1 = num[bestLabels==0]
n2 = num[bestLabels==1]

# 繪製分類結果
# 繪製原始資料
plt.plot(np.ones(len(n1)),n1,'ro')
plt.plot(np.ones(len(n2)),n2,'bo')
# 繪製中心點
#plt.plot([1],centers[0],'rx')
#plt.plot([1],centers[1],'bx')
plt.show()

例2:

有兩種物體:

物體1的長和寬都在 [0,20] 內
物體2的長和寬都在[40,60] 內
使用隨機數模擬兩種物體的長度和寬度,並使用函式cv2.kmeans()對它們分類。

根據題目要求,主要步驟如下:

隨機生成資料,並將它們轉換為函式cv2.kmeans()可以處理的形式。
設定函式cv2.kmeans()的引數形式。
呼叫函式cv2.kmeans()。
根據函式cv2.kmeans()的返回值,確定分類結果。
繪製經過分類的資料及中心點,觀察分類結果。
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 隨機生成兩組數值
#長和寬都在[0,20]內
m1 = np.random.randint(0,20, (30,2))
#長和寬的大小都在[40,60]
m2 = np.random.randint(40,60, (30,2))
# 組合資料
m = np.vstack((m1, m2))
# 轉換為float32型別
m = np.float32(m)
# 呼叫kmeans模組
# 設定引數criteria值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# 呼叫kmeans函式
ret, label, center=cv2.kmeans(m,2, None, criteria,10, cv2.KMEANS_RANDOM_CENTERS)

'''
#列印返回值
print(ret)
print(label)
print(center)
'''
# 根據kmeans的處理結果,將資料分類,兩大類
res1 = m[label.ravel()==0]
res2 = m[label.ravel()==1]
# 繪製分類結果資料及中心點
plt.scatter(res1[:,0], res1[:,1], c = 'g', marker = 's')
plt.scatter(res2[:,0], res2[:,1], c = 'r', marker = 'o')
plt.scatter(center[0,0], center[0,1], s = 200, c = 'b', marker = 'o')
plt.scatter(center[1,0], center[1,1], s = 200, c = 'b', marker = 's')
plt.xlabel('Height'), plt.ylabel('Width')
plt.show()

例3:

使用函式cv2.kmeans()將灰度影象處理為只有兩個灰度級的二值影象。

需要對灰度影象內的色彩進行分類,將所有的畫素點劃分為兩類。然後,用這兩類的中心點畫素值替代原有畫素值,滿足題目的要求。

主要步驟如下:

影象預處理

讀取影象,並將影象轉換為函式cv2.kmeans()可以處理的形式。

在讀取影象時,如果是3個通道的RGB影象,需要將影象的RGB值處理為一個單獨的特徵值。具體實現時,用函式cv2.reshape()完成對影象特徵值的調整。

為了滿足函式cv2.kmeans()的要求,需要將影象的資料型別轉換為numpy.float32型別。

設定函式cv2.kmeans()的引數形式

設定引數criteria的值為“(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)”,讓函式cv2.kmeans()在達到一定精度或者達到一定迭代次數時,即停止迭代。

設定引數K的值為2,將所有畫素劃分為兩類。

呼叫函式cv2.kmeans()

呼叫函式cv2.kmeans(),得到距離值、分類中心點和分類標籤,用於後續操作。

值替換

將畫素點的值替換為當前分類的中心點的畫素值。

顯示變換前後的影象

分別顯示原始影象和二值化影象。

import numpy as np
import cv2
import matplotlib.pyplot as plt
# 讀取待處理影象
img = cv2.imread('./img/hand2.png')
# 使用reshape將一個畫素點的RGB值作為一個單元處理
data = img.reshape((-1,3)) # n行 3列
# 轉換為kmeans可以處理的型別
data = np.float32(data)
# 呼叫kmeans模組
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K =2
ret, label, center=cv2.kmeans(data, K, None, criteria,10, cv2.KMEANS_RANDOM_CENTERS)

# 轉換為uint8資料型別,將每個畫素點都賦值為當前分類的中心點畫素值
# 將center的值轉換為uint8
center = np.uint8(center)
# 使用center內的值替換原畫素點的值
res1 = center[label.flatten()] # 根據索引來取值,最後結果的大小同索引的大小
# 使用reshape調整替換後的影象
res2 = res1.reshape((img.shape))
# 顯示處理結果
plt.subplot(121)
plt.imshow(img[:,:,::-1])
plt.axis('off')
plt.subplot(122)
plt.imshow(res2[:,:,::-1])
plt.axis('off')
plt.show()

調整程式中的K值,就能改變影象的顯示結果。例如,K=8,則可以讓影象顯示8個灰度級。

參考:https://blog.csdn.net/first_bug/article/details/123514692