手機(jī)網(wǎng)站建設(shè)項(xiàng)目seo店鋪描述
機(jī)器學(xué)習(xí)——聚類算法一
文章目錄
- 前言
- 一、基于numpy實(shí)現(xiàn)聚類
- 二、K-Means聚類
- 2.1. 原理
- 2.2. 代碼實(shí)現(xiàn)
- 2.3. 局限性
- 三、層次聚類
- 3.1. 原理
- 3.2. 代碼實(shí)現(xiàn)
- 四、DBSCAN算法
- 4.1. 原理
- 4.2. 代碼實(shí)現(xiàn)
- 五、區(qū)別與相同點(diǎn)
- 1. 區(qū)別:
- 2. 相同點(diǎn):
- 總結(jié)
前言
在機(jī)器學(xué)習(xí)中,有多種聚類算法可以用于將數(shù)據(jù)集中的樣本按照相似性進(jìn)行分組。本文將介紹一些常見的聚類算法:
- K-Means聚類
- 層次聚類
- DBSCAN算法
一、基于numpy實(shí)現(xiàn)聚類
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from numpy.linalg import norm
import random
np.random.seed(42)
data = np.random.randn(100,2) #生成一個(gè)包含100個(gè)樣本點(diǎn)的隨機(jī)數(shù)據(jù)集,每個(gè)樣本有2個(gè)特征
df = pd.DataFrame(data= data,columns=["x1","x2"])x1_min, x1_max, x2_min, x2_max = df.x1.min(), df.x1.max() ,df.x2.min(), df.x2.max()# 初始化兩個(gè)質(zhì)心
centroid_1 = np.array([random.uniform(x1_min, x1_max), random.uniform(x2_min, x2_max)])
centroid_2 = np.array([random.uniform(x1_min, x1_max), random.uniform(x2_min, x2_max)])data = df.values
#設(shè)置迭代次數(shù)為10
for i in range(10):clusters = []for point in data:centroid_1_dist = norm(centroid_1- point) #計(jì)算兩點(diǎn)之間的距離centroid_2_dist = norm(centroid_2- point)cluster = 1if centroid_1_dist > centroid_2_dist:cluster = 2clusters.append(cluster)df["cluster"] = clusters#更換質(zhì)心(即迭代聚類點(diǎn))
centroid_1 = [round(df[df.cluster == 1].x1.mean(),3), round(df[df.cluster == 1].x2.mean(),3)]
centroid_2 = [round(df[df.cluster == 2].x1.mean(),3), round(df[df.cluster == 2].x2.mean(),3)]plt.scatter(x1, x2, c=df["cluster"])
plt.scatter(centroid_1,centroid_2, marker='x', color='red')
plt.show()
二、K-Means聚類
2.1. 原理
K-means 是一種迭代算法,它將數(shù)據(jù)集按照距離劃分為 K 個(gè)簇(其中K是用戶預(yù)先指定的簇的數(shù)量),每個(gè)簇代表一個(gè)聚類(聚類后同一類數(shù)據(jù)盡可能聚集到一起,不同類數(shù)據(jù)分離)。實(shí)現(xiàn)步驟如下:
- 隨機(jī)初始化K個(gè)質(zhì)心,每個(gè)質(zhì)心代表一個(gè)簇
- 將每個(gè)樣本點(diǎn)分配到距離其最近的質(zhì)心所代表的簇。(如此就形成了K個(gè)簇)
- 更新每個(gè)簇的質(zhì)心,(即計(jì)算每個(gè)簇中樣本點(diǎn)的平均值)
- 重復(fù)步驟2和步驟3,直到質(zhì)心的位置不再改變或達(dá)到預(yù)定的迭代次數(shù)。
2.2. 代碼實(shí)現(xiàn)
- 導(dǎo)入數(shù)據(jù)集,以鳶尾花(iris)數(shù)據(jù)集為例:
from sklearn.datasets import load_iris
import pandas as pd# 加載數(shù)據(jù)集
iris = load_iris()#查看數(shù)據(jù)集信息
print(iris.keys())
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])#獲取特征數(shù)據(jù)
data = iris["data"]# 獲取標(biāo)簽數(shù)據(jù)
target = iris["target"]
print(pd.Series(target).unique())
[0 1 2]#查看分類名
print(iris["target_names"])
['setosa' 'versicolor' 'virginica']#整合到數(shù)據(jù)框
import pandas as pd
df = pd.DataFrame(data= iris["data"],columns= iris["feature_names"])
print(df.head())sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
- 確定初始化質(zhì)點(diǎn)K的取值
肘部法則選擇聚類數(shù)目:
該方法適用于K值相對(duì)較小的情況,隨著聚類數(shù)目的增加,聚類誤差(也稱為SSE,Sum of Squared Errors)會(huì)逐漸減小。然而,當(dāng)聚類數(shù)目達(dá)到一定閾值后,聚類誤差的減小速度會(huì)變緩,形成一個(gè)類似手肘的曲線。這個(gè)手肘點(diǎn)對(duì)應(yīng)的聚類數(shù)目就是肘部法則選擇的合適聚類數(shù)目。
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
sse = []
# 設(shè)置聚類數(shù)目的范圍
k_range = range(1, 10)
# 計(jì)算每個(gè)聚類數(shù)目對(duì)應(yīng)的 SSE
for k in k_range:kmeans = KMeans(n_clusters=k,random_state = 42)kmeans.fit(df)sse.append(kmeans.inertia_)# 繪制聚類數(shù)目與 SSE 之間的曲線圖
plt.style.use("ggplot")
plt.plot(k_range, sse,"r-o")
plt.xlabel('Number of K')
plt.ylabel('SSE')
plt.title('Elbow Method')
plt.show()
從圖中可看出,當(dāng)K=3時(shí),該曲線變得比較平緩,則該點(diǎn)為肘部點(diǎn)。即最佳的聚類數(shù)目為K=3
- 從sklean中調(diào)用k-Means算法模型
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3,max_iter= 400,random_state=42)
kmeans.fit(df)
print(kmeans.cluster_centers_)
y_kmeans = kmeans.labels_
df["y_kmeans"] = y_kmeans
- 可視化聚類結(jié)果
繪制平面圖:
plt.scatter(df["sepal length (cm)"], df["sepal width (cm)"], c=df["y_kmeans"], cmap='viridis')
# 繪制聚類中心
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], c='red', marker='x', s=100)
plt.xlabel('Sepal Length')
plt.ylabel('Sepal Width')
plt.title('K-Means Clustering')
handles, labels = sc.legend_elements()
plt.legend(handles, labels)
plt.show()
繪制三維圖:
# 創(chuàng)建3D圖形對(duì)象
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
# 繪制散點(diǎn)圖
sc = ax.scatter(df["sepal length (cm)"], df["sepal width (cm)"], df["petal length (cm)"], c=df["y_kmeans"], cmap='viridis')# 繪制聚類中心
ax.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], kmeans.cluster_centers_[:, 2], c='red', marker='x', s=100)ax.set_xlabel('Sepal Length')
ax.set_ylabel('Sepal Width')
ax.set_zlabel('Petal Length')
ax.set_title('K-Means Clustering')# 添加圖例
handles, labels = sc.legend_elements()
ax.legend(handles, labels)plt.show()
2.3. 局限性
k-Means算法通過距離來度量樣本之間的相似性,因此對(duì)于非凸形狀的聚類,算法可能無法正確地將樣本劃分到正確的聚類中。
k-Means算法對(duì)噪聲和離群點(diǎn)敏感。這些異常值可能會(huì)影響到聚類結(jié)果,使得聚類變得不準(zhǔn)確
需要事先指定聚類的數(shù)量k,而且對(duì)結(jié)果敏感。如果選擇的聚類數(shù)量不合適,會(huì)導(dǎo)致聚類結(jié)果不準(zhǔn)確或不理想。
比如這種情況:
三、層次聚類
3.1. 原理
層次聚類(Agglomerative clustering)算法是一種基于樹狀結(jié)構(gòu)的聚類方法,分為凝聚型和分裂型層次聚類。
分裂型層次聚類從整個(gè)數(shù)據(jù)集作為一個(gè)簇開始,然后逐步將簇分裂為更小的簇,直到達(dá)到預(yù)定的簇的數(shù)量或達(dá)到某個(gè)停止準(zhǔn)則。
凝聚型層次聚類將數(shù)據(jù)集中的樣本逐步合并為越來越大的簇。
即從N個(gè)簇開始(每個(gè)樣本為一個(gè)簇),在每個(gè)步驟中合并兩個(gè)最相似的簇,直到達(dá)到某個(gè)停止準(zhǔn)則。
如圖所示,從上(下)往下(上):
優(yōu)點(diǎn)是可以直觀地展示數(shù)據(jù)點(diǎn)之間的相似性關(guān)系,并且不一定要預(yù)先指定聚類簇的數(shù)量。
層次聚類的缺點(diǎn)是計(jì)算復(fù)雜度較高,且對(duì)數(shù)據(jù)的噪聲和異常值比較敏感。
3.2. 代碼實(shí)現(xiàn)
參數(shù) linkage: 用于指定鏈接算法。
“ward” : 單鏈接,即兩個(gè)簇的樣本對(duì)之間距離的min
“complete”: 全鏈接,即兩個(gè)簇的樣本對(duì)之間距離的max
“average”: 均鏈接,即兩個(gè)簇的樣本對(duì)之間距離的mean
參數(shù) affinity : 用于計(jì)算距離。
“euclidean”:使用歐幾里德距離來計(jì)算數(shù)據(jù)點(diǎn)之間的距離(這是默認(rèn)的距離度量方法)。
“manhattan”:使用曼哈頓距離來計(jì)算數(shù)據(jù)點(diǎn)之間的距離,它是兩個(gè)點(diǎn)在所有維度上絕對(duì)值之和的總和。
“cosine”:使用余弦相似度來計(jì)算數(shù)據(jù)點(diǎn)之間的距離。
from sklearn.cluster import AgglomerativeClustering
cluster = AgglomerativeClustering()
print(cluster.fit_predict(df))cluster = AgglomerativeClustering(n_clusters= 3 ,linkage= "complete",affinity="manhattan")
cluster.fit(df)
df["cluster"] = cluster.labels_
print(cluster.labels_)# 創(chuàng)建3D圖形對(duì)象
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
plt.style.use("ggplot")for i in range(len(df["cluster"])):if df["cluster"][i] == 0:ax.scatter(df["sepal length (cm)"][i], df["sepal width (cm)"][i], df["petal length (cm)"][i],c = "red")elif df["cluster"][i] ==1:ax.scatter(df["sepal length (cm)"][i], df["sepal width (cm)"][i], df["petal length (cm)"][i],c = "blue")else:ax.scatter(df["sepal length (cm)"][i], df["sepal width (cm)"][i], df["petal length (cm)"][i],c = "yellow")ax.set_xlabel('Sepal Length')
ax.set_ylabel('Sepal Width')
ax.set_zlabel('Petal Length')
ax.set_title('Clustering')
plt.show()
四、DBSCAN算法
4.1. 原理
DBSCAN是一種基于密度的聚類算法,它能夠發(fā)現(xiàn)任意形狀的聚類簇,并且能夠識(shí)別出噪聲點(diǎn),它將樣本劃分為核心點(diǎn)、邊界點(diǎn)和噪聲點(diǎn)。算法的步驟如下:
-
隨機(jī)選擇一個(gè)未訪問的樣本點(diǎn)。根據(jù)設(shè)置的距離半徑(eps),稱在這一范圍的區(qū)域?yàn)?strong>該樣本實(shí)例的鄰域
-
如果該樣本點(diǎn)的鄰域內(nèi)樣本數(shù)大于設(shè)定的閾值(min_samples),則將其標(biāo)記為核心點(diǎn),并將其鄰域內(nèi)的樣本點(diǎn)加入到同一個(gè)簇中。
-
如果該樣本點(diǎn)的鄰域內(nèi)樣本數(shù)小于設(shè)定的閾值,則將其標(biāo)記為邊界點(diǎn)。
-
重復(fù)以上步驟,直到所有樣本點(diǎn)都被訪問。
-
最后,任何不是核心點(diǎn),且鄰域中沒有實(shí)例樣本的樣本點(diǎn)都將被標(biāo)記為噪聲點(diǎn)
4.2. 代碼實(shí)現(xiàn)
from sklearn.cluster import DBSCAN
cluster = DBSCAN(eps= 0.6 , min_samples= 10)
cluster.fit(df)
df["cluster"] = cluster.labels_
print(df)#-1代表噪聲點(diǎn)
print(df["cluster"].value_counts())1 880 49
-1 13
Name: cluster, dtype: int64sc = plt.scatter(df["sepal length (cm)"],df["sepal width (cm)"],c = df["cluster"])
plt.title('DBSCAN Clustering')
handles, labels = sc.legend_elements()
plt.legend(handles, labels)
plt.show()
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons# 生成隨機(jī)數(shù)據(jù)
X, y = make_moons(n_samples=200, noise=0.05)
print(X)dbscan = DBSCAN(eps=0.3, min_samples=5)
dbscan.fit(X)# 獲取聚類標(biāo)簽
labels = dbscan.labels_#因?yàn)樵O(shè)置的noise很小,故沒有噪聲點(diǎn)
print(pd.Series(labels).value_counts())
0 100
1 100
dtype: int64# 繪制聚類結(jié)果
plt.scatter(X[:, 0], X[:, 1], c=labels)
plt.title('DBSCAN Clustering')
handles, labels = sc.legend_elements()
plt.legend(handles, labels)
plt.show()
五、區(qū)別與相同點(diǎn)
1. 區(qū)別:
-
K-means是一種劃分聚類算法,它將數(shù)據(jù)集劃分為固定數(shù)量的簇(一定要預(yù)先指定簇的數(shù)量),而層次聚類(不一定要指定簇的數(shù)量)和DBSCAN算法(需要指定鄰域半徑和最小樣本數(shù)),它們可以自動(dòng)確定簇的數(shù)量。
-
K-means和層次聚類算法都假設(shè)簇具有相同的形狀和大小,而DBSCAN算法可以發(fā)現(xiàn)任意形狀和大小的簇。
-
K-means和層次聚類算法都對(duì)異常值敏感,而DBSCAN算法對(duì)異常值不敏感。(可去掉噪聲點(diǎn))
2. 相同點(diǎn):
K-means、層次聚類和DBSCAN算法都是無監(jiān)督學(xué)習(xí)算法中的聚類算法,它們不依賴于標(biāo)簽信息。
這些算法都使用距離或相似性度量來度量樣本之間的相似性或距離。
總結(jié)
本文從最開始的自己實(shí)現(xiàn)聚類到后面的三個(gè)機(jī)器學(xué)習(xí)中聚類算法:( K-Means 、層次聚類、DBSCAN聚類)的學(xué)習(xí),再到后面對(duì)這三個(gè)算法的比較與總結(jié)。加深了對(duì)聚類原理的了解。
我住長(zhǎng)江頭,君住長(zhǎng)江尾;日日思君不見君
–2023-8-31 筑基篇