Python實現(xiàn)聚類K-means算法詳解
K-means(K均值)算法是最簡單的一種聚類算法,它期望最小化平方誤差

注:為避免運行時間過長,通常設(shè)置一個最大運行輪數(shù)或最小調(diào)整幅度閾值,若到達(dá)最大輪數(shù)或調(diào)整幅度小于閾值,則停止運行。
下面我們用python來實現(xiàn)一下K-means算法:我們先嘗試手動實現(xiàn)這個算法,再用sklearn庫中的KMeans類來實現(xiàn)。數(shù)據(jù)我們采用《機(jī)器學(xué)習(xí)》的西瓜數(shù)據(jù)(P202表9.1):
# 下面的內(nèi)容保存在 melons.txt 中 # 第一列為西瓜的密度;第二列為西瓜的含糖率。我們要把這30個西瓜分為3類 0.697 0.460 0.774 0.376 0.634 0.264 0.608 0.318 0.556 0.215 0.403 0.237 0.481 0.149 0.437 0.211 0.666 0.091 0.243 0.267 0.245 0.057 0.343 0.099 0.639 0.161 0.657 0.198 0.360 0.370 0.593 0.042 0.719 0.103 0.359 0.188 0.339 0.241 0.282 0.257 0.748 0.232 0.714 0.346 0.483 0.312 0.478 0.437 0.525 0.369 0.751 0.489 0.532 0.472 0.473 0.376 0.725 0.445 0.446 0.459
手動實現(xiàn)
我們用到的庫有matplotlib和numpy,如果沒有需要先用pip安裝一下。
import random import numpy as np import matplotlib.pyplot as plt
下面定義一些數(shù)據(jù):
k = 3 # 要分的簇數(shù) rnd = 0 # 輪次,用于控制迭代次數(shù)(見上文) ROUND_LIMIT = 100 # 輪次的上限 THRESHOLD = 1e-10 # 單輪改變距離的閾值,若改變幅度小于該閾值,算法終止 melons = [] # 西瓜的列表 clusters = [] # 簇的列表,clusters[i]表示第i簇包含的西瓜
從melons.txt讀取數(shù)據(jù),保存在列表中:
f = open('melons.txt', 'r')
for line in f:
# 把字符串轉(zhuǎn)化為numpy中的float64類型
melons.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))從 m m m個數(shù)據(jù)中隨機(jī)挑選出 k k k個,對應(yīng)上面算法的第 1 1 1行:
# random的sample函數(shù)從列表中隨機(jī)挑選出k個樣本(不重復(fù))。我們在這里把這些樣本作為均值向量 mean_vectors = random.sample(melons, k)
下面是算法的主要部分。
# 這個while對應(yīng)上面算法的2-17行
while True:
rnd += 1 # 輪次增加
change = 0 # 把改變幅度重置為0
# 清空對簇的劃分,對應(yīng)上面算法的第3行
clusters = []
for i in range(k):
clusters.append([])
# 這個for對應(yīng)上面算法的4-8行
for melon in melons:
'''
argmin 函數(shù)找出容器中最小的下標(biāo),在這里這個目標(biāo)容器是
list(map(lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors)),
它表示melon與mean_vectors中所有向量的距離列表。
(numpy.linalg.norm計算向量的范數(shù),ord = 2即歐幾里得范數(shù),或模長)
'''
c = np.argmin(
list(map( lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors))
)
clusters[c].append(melon)
# 這個for對應(yīng)上面算法的9-16行
for i in range(k):
# 求每個簇的新均值向量
new_vector = np.zeros((1,2))
for melon in clusters[i]:
new_vector += melon
new_vector /= len(clusters[i])
# 累加改變幅度并更新均值向量
change += np.linalg.norm(mean_vectors[i] - new_vector, ord = 2)
mean_vectors[i] = new_vector
# 若超過設(shè)定的輪次或者變化幅度<預(yù)先設(shè)定的閾值,結(jié)束算法
if rnd > ROUND_LIMIT or change < THRESHOLD:
break
print('最終迭代%d輪'%rnd)最后我們繪圖來觀察一下劃分的結(jié)果:
colors = ['red', 'green', 'blue']
# 每個簇?fù)Q一下顏色,同時迭代簇和顏色兩個列表
for i, col in zip(range(k), colors):
for melon in clusters[i]:
# 繪制散點圖
plt.scatter(melon[0], melon[1], color = col)
plt.show()劃分結(jié)果(由于最開始的 k k k個均值向量隨機(jī)選取,每次劃分的結(jié)果可能會不同):

完整代碼:
import random
import numpy as np
import matplotlib.pyplot as plt
k = 3
rnd = 0
ROUND_LIMIT = 10
THRESHOLD = 1e-10
melons = []
clusters = []
f = open('melons.txt', 'r')
for line in f:
melons.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))
mean_vectors = random.sample(melons, k)
while True:
rnd += 1
change = 0
clusters = []
for i in range(k):
clusters.append([])
for melon in melons:
c = np.argmin(
list(map( lambda vec: np.linalg.norm(melon - vec, ord = 2), mean_vectors))
)
clusters[c].append(melon)
for i in range(k):
new_vector = np.zeros((1,2))
for melon in clusters[i]:
new_vector += melon
new_vector /= len(clusters[i])
change += np.linalg.norm(mean_vectors[i] - new_vector, ord = 2)
mean_vectors[i] = new_vector
if rnd > ROUND_LIMIT or change < THRESHOLD:
break
print('最終迭代%d輪'%rnd)
colors = ['red', 'green', 'blue']
for i, col in zip(range(k), colors):
for melon in clusters[i]:
plt.scatter(melon[0], melon[1], color = col)
plt.show()sklearn庫中的KMeans
這種經(jīng)典算法顯然不需要我們反復(fù)地造輪子,被廣泛使用的python機(jī)器學(xué)習(xí)庫sklearn已經(jīng)提供了該算法的實現(xiàn)。sklearn的官方文檔中給了我們一個示例:
>>> from sklearn.cluster import KMeans
>>> import numpy as np
>>> X = np.array([[1, 2], [1, 4], [1, 0],
... [10, 2], [10, 4], [10, 0]])
>>> kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
>>> kmeans.labels_
array([1, 1, 1, 0, 0, 0], dtype=int32)
>>> kmeans.predict([[0, 0], [12, 3]])
array([1, 0], dtype=int32)
>>> kmeans.cluster_centers_
array([[10., 2.],
[ 1., 2.]])可以看出,X即要聚類的數(shù)據(jù)(1,2),(1,4),(1,0)等。KMeans類的初始化參數(shù)n_clusters即簇數(shù) k k k;random_state是用于初始化選取 k k k個向量的隨機(jī)數(shù)種子;kmeans.labels_即每個點所屬的簇;kmeans.predict方法預(yù)測新的數(shù)據(jù)屬于哪個簇;kmeans.cluster_centers_返回每個簇的中心。
我們就改造一下這個簡單的示例,完成對上面西瓜的聚類。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
X = []
f = open('melons.txt', 'r')
for line in f:
X.append(np.array(line.split(' '), dtype = np.string_).astype(np.float64))
kmeans = KMeans(n_clusters = 3, random_state = 0).fit(X)
colors = ['red', 'green', 'blue']
for i, cluster in enumerate(kmeans.labels_):
plt.scatter(X[i][0], X[i][1], color = colors[cluster])
plt.show()運行結(jié)果如下,可以看到和我們手寫的聚類結(jié)果基本一致:

到此這篇關(guān)于Python實現(xiàn)聚類K-means算法詳解的文章就介紹到這了,更多相關(guān)Python K-means算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Django中對數(shù)據(jù)查詢結(jié)果進(jìn)行排序的方法
這篇文章主要介紹了Django中對數(shù)據(jù)查詢結(jié)果進(jìn)行排序的方法,利用Python代碼代替SQL進(jìn)行一些簡單的操作,需要的朋友可以參考下2015-07-07
淺談配置OpenCV3 + Python3的簡易方法(macOS)
下面小編就為大家分享一篇淺談配置OpenCV3 + Python3的簡易方法(macOS),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04
Mac在python3環(huán)境下安裝virtualwrapper遇到的問題及解決方法
這篇文章主要介紹了Mac在python3環(huán)境下安裝virtualwrapper遇到的問題及解決方法,我在使用mac安裝virtualwrapper的時候遇到了問題,搞了好長時間,,在這里總結(jié)一下分享出來,供遇到相同的問題的朋友使用,少走些彎路,需要的朋友可以參考下2019-07-07
python字典與json轉(zhuǎn)換的方法總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于python字典與json轉(zhuǎn)換的方法總結(jié)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。2020-12-12

