數(shù)據(jù)分析大佬用Python代碼教會(huì)你Mean Shift聚類
MeanShift算法可以稱之為均值漂移聚類,是基于聚類中心的聚類算法,但和k-means聚類不同的是,不需要提前設(shè)定類別的個(gè)數(shù)k。在MeanShift算法中聚類中心是通過(guò)一定范圍內(nèi)樣本密度來(lái)確定的,通過(guò)不斷更新聚類中心,直到最終的聚類中心達(dá)到終止條件。整個(gè)過(guò)程可以看下圖,我覺(jué)得還是比較形象的。
MeanShift向量
MeanShift向量是指對(duì)于樣本X1,在以樣本點(diǎn)X1為中心,半徑為h的高維球區(qū)域內(nèi)的所有樣本點(diǎn)X的加權(quán)平均值,如下所示,同時(shí)也是樣本點(diǎn)X1更新后的坐標(biāo)。
而終止條件則是指 | Mh(X) - X |<ε,滿足條件則樣本點(diǎn)X1停止更新,否則將以Mh(X)為新的樣本中心重復(fù)上述步驟。
核函數(shù)
核函數(shù)在機(jī)器學(xué)習(xí)(SVM,LR)中出現(xiàn)的頻率是非常高的,你可以把它看做是一種映射,是計(jì)算映射到高維空間之后的內(nèi)積的一種簡(jiǎn)便方法。在這個(gè)算法中將使用高斯核,其函數(shù)形式如下。
h表示帶寬,當(dāng)帶寬h一定時(shí),兩個(gè)樣本點(diǎn)距離越近,其核函數(shù)值越大;當(dāng)兩個(gè)樣本點(diǎn)距離一定時(shí),h越大,核函數(shù)值越小。核函數(shù)代碼如下,gaosi_value為以樣本點(diǎn)X1為中心,半徑為h的高維球范圍內(nèi)所有樣本點(diǎn)與X1的高斯核函數(shù)值,是一個(gè)(m,1)的矩陣。
def gaussian_kernel(self,distant): m=shape(distant)[1]#樣本數(shù) gaosi=mat(zeros((m,1))) for i in range(m): gaosi[i][0]=(distant.tolist()[0][i]*distant.tolist()[0][i]*(-0.5)/(self.bandwidth*self.bandwidth)) gaosi[i][0]=exp(gaosi[i][0]) q=1/(sqrt(2*pi)*self.bandwidth) gaosi_value=q*gaosi return gaosi_value
MeanShift向量與核函數(shù)
在01中有提到MeanShift向量是指對(duì)于樣本X1,在以樣本點(diǎn)X1為中心,半徑為h的高維球區(qū)域內(nèi)的所有樣本點(diǎn)X的加權(quán)平均值。但事實(shí)上是不同點(diǎn)對(duì)于樣本X1的貢獻(xiàn)程度是不一樣的,因此將權(quán)值(1/k)更改為每個(gè)樣本與樣本點(diǎn)X1的核函數(shù)值。改進(jìn)后的MeanShift向量如下所示。
其中
就是指高斯核函數(shù),Sh表示在半徑h內(nèi)的所有樣本點(diǎn)集合。
MeanShift算法原理
在MeanShift算法中實(shí)際上利用了概率密度,求得概率密度的局部最優(yōu)解。
對(duì)于一個(gè)概率密度函數(shù)f(x),已知一個(gè)概率密度函數(shù)f(X),其核密度估計(jì)為
其中K(X)是單位核,概率密度函數(shù)f(X)的梯度估計(jì)為
其中G(X)=-K'(X)。第一個(gè)中括號(hào)是以G(X)為核函數(shù)對(duì)概率密度的估計(jì),第二個(gè)中括號(hào)是MeanShift 向量。因此MeanShift向量是與概率密度函數(shù)的梯度成正比的,總是指向概率密度增加的方向。
而對(duì)于MeanShift向量,可以將其變形為下列形式,其中mh(x)為樣本點(diǎn)X更新后的位置。
MeanShift算法流程
在未被標(biāo)記的數(shù)據(jù)點(diǎn)中隨機(jī)選擇一個(gè)點(diǎn)作為起始中心點(diǎn)X;
找出以X為中心半徑為radius的區(qū)域中出現(xiàn)的所有數(shù)據(jù)點(diǎn),認(rèn)為這些點(diǎn)同屬于一個(gè)聚類C。同時(shí)在該聚類中記錄數(shù)據(jù)點(diǎn)出現(xiàn)的次數(shù)加1。
以X為中心點(diǎn),計(jì)算從X開(kāi)始到集合M中每個(gè)元素的向量,將這些向量相加,得到向量Mh(X)。
mh(x) =Mh(X) + X。即X沿著Mh(X)的方向移動(dòng),移動(dòng)距離是||Mh(X)||。
重復(fù)步驟2、3、4,直到Mh(X)的很小(就是迭代到收斂),記住此時(shí)的X。注意,這個(gè)迭代過(guò)程中遇到的點(diǎn)都應(yīng)該歸類到簇C。
如果收斂時(shí)當(dāng)前簇C的center與其它已經(jīng)存在的簇C2中心的距離小于閾值,那么把C2和C合并,數(shù)據(jù)點(diǎn)出現(xiàn)次數(shù)也對(duì)應(yīng)合并。否則,把C作為新的聚類。
重復(fù)1、2、3、4、5直到所有的點(diǎn)都被標(biāo)記為已訪問(wèn)。
分類:根據(jù)每個(gè)類,對(duì)每個(gè)點(diǎn)的訪問(wèn)頻率,取訪問(wèn)頻率最大的那個(gè)類,作為當(dāng)前點(diǎn)集的所屬類。
TIPS:每一個(gè)樣本點(diǎn)都需要計(jì)算其漂移均值,并根據(jù)計(jì)算出的漂移均值進(jìn)行移動(dòng),直至滿足終止條件,最終得到的均值漂移點(diǎn)為該點(diǎn)的聚類中心點(diǎn)。
MeanShift算法代碼
from numpy import *from matplotlib import pyplot as plt
class mean_shift(): def __init__(self): #帶寬 self.bandwidth=2 #漂移點(diǎn)收斂條件 self.mindistance=0.001 #簇心距離,小于該值則兩簇心合并 self.cudistance=2.5
def gaussian_kernel(self,distant): m=shape(distant)[1]#樣本數(shù) gaosi=mat(zeros((m,1))) for i in range(m): gaosi[i][0]=(distant.tolist()[0][i]*distant.tolist()[0][i]*(-0.5)/(self.bandwidth*self.bandwidth)) gaosi[i][0]=exp(gaosi[i][0]) q=1/(sqrt(2*pi)*self.bandwidth) gaosi_value=q*gaosi return gaosi_value
def load_data(self): X =array([ [-4, -3.5], [-3.5, -5], [-2.7, -4.5], [-2, -4.5], [-2.9, -2.9], [-0.4, -4.5], [-1.4, -2.5], [-1.6, -2], [-1.5, -1.3], [-0.5, -2.1], [-0.6, -1], [0, -1.6], [-2.8, -1], [-2.4, -0.6], [-3.5, 0], [-0.2, 4], [0.9, 1.8], [1, 2.2], [1.1, 2.8], [1.1, 3.4], [1, 4.5], [1.8, 0.3], [2.2, 1.3], [2.9, 0], [2.7, 1.2], [3, 3], [3.4, 2.8], [3, 5], [5.4, 1.2], [6.3, 2],[0,0],[0.2,0.2],[0.1, 0.1],[-4, -3.5]]) x,y=[],[] for i in range(shape(X)[0]): x.a(chǎn)ppend(X[i][0]) y.a(chǎn)ppend(X[i][1]) plt.scatter(x,y,c='r') # plt.plot(x, y) plt.show() classlable=mat(zeros((shape(X)[0],1))) return X,classlable
def distance(self,a,b): v=a-b return sqrt(v*mat(v).T).tolist()[0][0] def shift_point(self,point,data,clusterfrequency): sum=0 n=shape(data)[0] ou=mat(zeros((n,1))) t=mat(zeros((n,1))) newdata=[] for i in range(n): # print(self.distance(point,data[i])) d=self.distance(point,data[i]) if d<self.bandwidth: ou[i][0] =d t[i][0]=1 newdata.a(chǎn)ppend(data[i]) clusterfrequency[i]=clusterfrequency[i]+1 gaosi=self.gaussian_kernel(ou[t==1]) meanshift=gaosi.T*mat(newdata) return meanshift/gaosi.sum(),clusterfrequency
def group2(self,dataset,clusters,m): data=[] fre=[] for i in clusters: i['data']=[] fre.a(chǎn)ppend(i['frequnecy']) for j in range(m): n=where(array(fre)[:,j]==max(array(fre)[:,j]))[0][0] data.a(chǎn)ppend(n) clusters[n]['data'].a(chǎn)ppend(dataset[j]) print("一共有%d個(gè)簇心" % len(set(data))) # print(clusters) # print(data) return clusters
def plot(self,dataset,clust): colors = 10 * ['r', 'g', 'b', 'k', 'y','orange','purple'] plt.figure(figsize=(5, 5)) plt.xlim((-8, 8)) plt.ylim((-8, 8)) plt.scatter(dataset[:, 0],dataset[:, 1], s=20) theta = linspace(0, 2 * pi, 800) for i in range(len(clust)): cluster = clust[i] data = array(cluster['data']) if len(data): plt.scatter(data[:, 0], data[:, 1], color=colors[i], s=20) centroid =cluster['centroid'].tolist()[0] plt.scatter(centroid[0], centroid[1], color=colors[i], marker='x', s=30) x, y = cos(theta) * self.bandwidth + centroid[0], sin(theta) * self.bandwidth + centroid[1] plt.plot(x, y, linewidth=1, color=colors[i]) plt.show()
def mean_shift_train(self): dataset, classlable = self.load_data() m = shape(dataset)[0] clusters = [] for i in range(m): max_distance = inf cluster_centroid = dataset[i] # print(cluster_centroid) cluster_frequency =zeros((m,1)) while max_distance>self.mindistance: w,cluster_frequency = self.shift_point(cluster_centroid,dataset,cluster_frequency) dis = self.distance(cluster_centroid, w) if dis < max_distance: max_distance = dis # print(max_distance) cluster_centroid = w has_same_cluster = False for cluster in clusters: if self.distance(cluster['centroid'],cluster_centroid)<self.cudistance: cluster['frequnecy']=cluster['frequnecy']+cluster_frequency has_same_cluster=True break if not has_same_cluster: clusters.a(chǎn)ppend({'frequnecy':cluster_frequency,'centroid':cluster_centroid}) clusters=self.group2(dataset,clusters,m) print(clusters) self.plot(dataset,clusters)
if __name__=="__main__": shift=mean_shift() shift.mean_shift_train()
得到的結(jié)果圖如下。
之后還會(huì)詳細(xì)解說(shuō)K-means聚類以及DBSCAN聚類,敬請(qǐng)關(guān)注。
發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
即日-11.13立即報(bào)名>>> 【在線會(huì)議】多物理場(chǎng)仿真助跑新能源汽車
-
11月20日火熱報(bào)名中>> 2024 智能家居出海論壇
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會(huì)議
-
12月19日立即報(bào)名>> 【線下會(huì)議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
即日-12.26火熱報(bào)名中>> OFweek2024中國(guó)智造CIO在線峰會(huì)
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書》
推薦專題
- 1 【一周車話】沒(méi)有方向盤和踏板的車,你敢坐嗎?
- 2 特斯拉發(fā)布無(wú)人駕駛車,還未迎來(lái)“Chatgpt時(shí)刻”
- 3 特斯拉股價(jià)大跌15%:Robotaxi離落地還差一個(gè)蘿卜快跑
- 4 馬斯克給的“驚喜”夠嗎?
- 5 打完“價(jià)格戰(zhàn)”,大模型還要比什么?
- 6 馬斯克致敬“國(guó)產(chǎn)蘿卜”?
- 7 神經(jīng)網(wǎng)絡(luò),誰(shuí)是盈利最強(qiáng)企業(yè)?
- 8 比蘋果偉大100倍!真正改寫人類歷史的智能產(chǎn)品降臨
- 9 諾獎(jiǎng)進(jìn)入“AI時(shí)代”,人類何去何從?
- 10 Open AI融資后成萬(wàn)億獨(dú)角獸,AI人才之爭(zhēng)開(kāi)啟
- 高級(jí)軟件工程師 廣東省/深圳市
- 自動(dòng)化高級(jí)工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級(jí)銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市