日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

dbscan算法python实现_挑子学习笔记:DBSCAN算法的python实现

發(fā)布時(shí)間:2023/12/13 python 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dbscan算法python实现_挑子学习笔记:DBSCAN算法的python实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)聚類(lèi)算法,是一種基于高密度連通區(qū)域的、基于密度的聚類(lèi)算法,能夠?qū)⒕哂凶銐蚋呙芏鹊膮^(qū)域劃分為簇(Cluster),并在具有噪聲的數(shù)據(jù)中發(fā)現(xiàn)任意形狀的簇。DBSCAN算法通過(guò)距離定義出一個(gè)密度函數(shù),計(jì)算出每個(gè)樣本附近的密度,從而根據(jù)每個(gè)樣本附近的密度值來(lái)找出那些樣本相對(duì)比較集中的區(qū)域,這些區(qū)域就是我們要找的簇。

1. DBSCAN算法的基本原理

其它聚類(lèi)方法大都是基于對(duì)象之間的距離進(jìn)行聚類(lèi),聚類(lèi)結(jié)果是球狀的簇。DBSCAN 算法利用簇的高密度連通性,尋找被低密度區(qū)域分離的高密度區(qū)域,可以發(fā)現(xiàn)任意形狀的簇,其基本思想是:對(duì)于一個(gè)簇中的每個(gè)對(duì)象,在其給定半徑的領(lǐng)域中包含的對(duì)象不能少于某一給定的最小數(shù)目。

DBSCAN算法中有兩個(gè)重要參數(shù):$\varepsilon$表示定義密度時(shí)的鄰域半徑,$M$ 表示定義核心點(diǎn)時(shí)的閾值。

考慮數(shù)據(jù)集合$X= \{x^{(1)}, x^{(2)},...,x^{(n)} \}$,引入以下概念與記號(hào)。

1. $\varepsilon$鄰域

設(shè)$x \in X$,稱(chēng)

\begin{equation*}

N_{\varepsilon}(x) = \{ y \in X: d(y,x) \le \varepsilon \}

\end{equation*}

為$X$的$\varepsilon$鄰域。顯然,$x \in N_{\varepsilon}(x)$。

為了簡(jiǎn)單起見(jiàn),節(jié)點(diǎn)$x^{(i)}$與其下標(biāo)$i$一一對(duì)應(yīng),引入記號(hào)

\begin{equation*}

N_{\varepsilon}(i) = \{ j: d(y^{(j)},x^{(i)}) \le \varepsilon; \; y^{(j)},x^{(i)} \in X \}

\end{equation*}

2. 密度

設(shè)$x \in X$,稱(chēng)$\rho(x) = |N_{\varepsilon}(x)|$為$x$的密度。密度是一個(gè)整數(shù),且依賴(lài)于半徑$\varepsilon$。

3. 核心點(diǎn)

設(shè)$x \in X$,若$\rho(x) \ge M$,則稱(chēng)$x$為$X$的核心點(diǎn)。記由$X$中所有核心點(diǎn)構(gòu)成的集合為$X_c$,并記$X_{nc}=X-X_c$表示$X$中所有非核心點(diǎn)構(gòu)成的集合。

4. 邊界點(diǎn)

若$x \in X_{nc}$,且$\exists y \in X$,滿足$y \in N_{\varepsilon}(x) \bigcap X_c$,即$X$的非核心點(diǎn)$x$的$\varepsilon$鄰域中存在核心點(diǎn),則稱(chēng)$x$ 為$X$的邊界點(diǎn)。記由$X$中所有邊界點(diǎn)構(gòu)成的集合為$X_{bd}$。

此外,邊界點(diǎn)也可以這么定義,若$x \in X_{nc}$,且$x$落在某個(gè)核心點(diǎn)的$\varepsilon$鄰域內(nèi),則稱(chēng)$x$為$X$的邊界點(diǎn)。一個(gè)邊界點(diǎn)可能同時(shí)落入一個(gè)或多個(gè)核心點(diǎn)的$\varepsilon$ 鄰域內(nèi)。

5. 噪聲點(diǎn)

記$X_{noi} = X - (X_c \bigcup X_{bd})$,若$x \in X_{noi}$,則稱(chēng)$x$為噪音點(diǎn)。

至此,我們嚴(yán)格給出了核心點(diǎn)、邊界點(diǎn)和噪音點(diǎn)的數(shù)學(xué)定義,且滿足$X = X_c \bigcup X_{bd} \bigcup X_{noi}$.

圖1:核心點(diǎn)、邊界點(diǎn)和噪聲點(diǎn)

直觀地說(shuō),核心點(diǎn)對(duì)應(yīng)稠密區(qū)域內(nèi)部的點(diǎn),邊界點(diǎn)對(duì)應(yīng)稠密區(qū)域邊緣的點(diǎn),而噪音點(diǎn)對(duì)應(yīng)稀疏區(qū)域中的點(diǎn)。

數(shù)據(jù)集通過(guò)聚類(lèi)形成的子集是簇。核心點(diǎn)位于簇的內(nèi)部,它確定無(wú)誤地屬于某個(gè)特定的簇;噪音點(diǎn)是數(shù)據(jù)集中的干擾數(shù)據(jù),它不屬于任何一個(gè)簇;邊界點(diǎn)是一類(lèi)特殊的點(diǎn),它位于一個(gè)或幾個(gè)簇的邊緣地帶,可能屬于一個(gè)簇,也可能屬于另外一個(gè)簇,其歸屬并不明確。

6. 直接密度可達(dá)

設(shè)$x,y \in X$. 若滿足$x \in X_c$,則稱(chēng)$y$是$x$從直接密度可達(dá)的。

7. 密度可達(dá)

設(shè)$p^{(1)}, p^{(2)},..., p^{(m)} \in X$,其中$m \ge 2$。若它們滿足:$p^ {(i+1)}$ 是從$p^{(i)}$直接密度可達(dá)的,其中$i = 1,2,...,m-1$,則稱(chēng)$p^ {(m)}$ 是從$p^{(1)}$ 中密度可達(dá)的。

7.1. 當(dāng)$m = 2$時(shí),密度可達(dá)即為直接密度可達(dá)。實(shí)際上,密度可達(dá)是直接密度可達(dá)的傳遞閉包。

7.2. 密度可達(dá)關(guān)系不具有對(duì)稱(chēng)性。若$p^{(m)}$是從$p^{(1)}$密度可達(dá)的,那么$p^ {(1)}$ 不一定是從$p^{(m)}$密度可達(dá)的。根據(jù)上述定義可知,$p^{(1)}, p^{(2)}, ..., p^{(m-1)}$必須為核心點(diǎn),而$p^{(m)}$可以是核心點(diǎn),也可以是邊界點(diǎn)。當(dāng)$p^ {(m)}$是邊界點(diǎn)時(shí),$p^{(1)}$一定不是從$p^{(m)}$密度可達(dá)的。

8. 密度相連

設(shè)$x,y,z \in X$,若$y$和$z$均是從$x$密度可達(dá)的,則稱(chēng)$y$和$z$是密度相連的。顯然,密度相連具有對(duì)稱(chēng)性。

9. 簇(cluster)

非空集合$C \subset X$,如果$C$滿足:對(duì)于$x,y \in X$

若$x \in C$,且$y$是從$x$密度可達(dá)的,則$y \in C$,

若$x \in C$,$y \in C$,則$x,y$是密度相連的。

則稱(chēng)$C$是$X$的一個(gè)簇。

DBSCAN 算法基于以下一個(gè)基本事實(shí):對(duì)于任一核心點(diǎn)$x$,數(shù)據(jù)集$X$中所有從$x$ 密度可達(dá)的數(shù)據(jù)點(diǎn)可以構(gòu)成一個(gè)完整的簇$C$,且$x \in C$。其核心思想描述如下:從某個(gè)選定的核心點(diǎn)出發(fā),不斷向密度可達(dá)的區(qū)域擴(kuò)張,從而得到一個(gè)包含核心點(diǎn)和邊界點(diǎn)的最大化區(qū)域,區(qū)域中任意兩點(diǎn)密度相連。

2.?DBSCAN算法的實(shí)現(xiàn)

《數(shù)據(jù)挖掘概念與技術(shù)》給出的算法偽代碼如下:

考慮數(shù)據(jù)集合$X= \{x^{(1)}, x^{(2)},..., x^{(n)} \}$。DBSCAN算法的目標(biāo)是將數(shù)據(jù)集合$X$分成$K$個(gè)簇及噪聲點(diǎn)集合,其中$K$也是由算法得到,為此,引入簇的標(biāo)記數(shù)組

\begin{equation*}

m_i =

\begin{cases}

j, & \text{若}x^{(i)}\text{屬于第}j\text{個(gè)簇}; \\

-1, & \text{若}x^{(i)}\text{為噪聲點(diǎn)}

\end{cases}

\end{equation*}

DBSCAN算法的目標(biāo)就是生成標(biāo)記數(shù)組$m_i, \; i=1,...,n$.

為了保證可以更有效地實(shí)現(xiàn)算法1中第3句隨機(jī)選擇一個(gè)unvisited對(duì)象$p$,設(shè)計(jì)了一個(gè)數(shù)據(jù)結(jié)構(gòu)visitlist,其中包含兩個(gè)列表visitedlist和unvisitedlist,分別用于存儲(chǔ)已訪問(wèn)的點(diǎn)和未訪問(wèn)的點(diǎn),每次從unvisitedlist 中取點(diǎn)可以保證每次取到的點(diǎn)都是未訪問(wèn)過(guò)的點(diǎn),實(shí)現(xiàn)代碼如下:

代碼1:visitlist數(shù)據(jù)結(jié)構(gòu)

1 #visitlist類(lèi)用于記錄訪問(wèn)列表

2 #unvisitedlist記錄未訪問(wèn)過(guò)的點(diǎn)

3 #visitedlist記錄已訪問(wèn)過(guò)的點(diǎn)

4 #unvisitednum記錄訪問(wèn)過(guò)的點(diǎn)數(shù)量

5 classvisitlist:6 def _init_(self, count=0):7 self.unvisitedlist=[i for i inrange(count)]8 self.visitedlist=list()9 self.unvisitednum=count10

11 defvisit(self, pointId):12 self.visitedlist.append(pointId)13 self.unvisitedlist.remove(pointId)14 self.unvisitednum -= 1

DBSCAN算法實(shí)現(xiàn)代碼如下:

代碼2:DBSCAN算法實(shí)現(xiàn)

1 importnumpy as np2 importmatplotlib.pyplot as plt3 importmath4 importrandom5

6 defdist(a, b):7 #計(jì)算a,b兩個(gè)元組的歐幾里得距離

8 return math.sqrt(np.power(a-b, 2).sum())9

10 defmy_dbscanl(dataSet, eps, minPts):11 #numpy.ndarray的 shape屬性表示矩陣的行數(shù)與列數(shù)

12 nPoints =dataSet.shape[0]13 #(1)標(biāo)記所有對(duì)象為unvisited

14 #在這里用一個(gè)類(lèi)vPoints進(jìn)行買(mǎi)現(xiàn)

15 vPoints = visitlist(count=nPoints)16 #初始化簇標(biāo)記列表C,簇標(biāo)記為 k

17 k = -1

18 C = [-1 for i inrange(nPoints)]19 while(vPoints.unvisitednum >0):20 #(3)隨機(jī)上選擇一個(gè)unvisited對(duì)象p

21 P =random.choice(vPoints.unvisitedlist)22 #(4)標(biāo)記p為visited

23 vPoints.visit(p)24 #(5)if p的$\varepsilon$-鄰域至少有MinPts個(gè)對(duì)象

25 #N是p的$\varepsilon$-鄰域點(diǎn)列表

26 N = [i for i in range(nPoints) if dist(dataSet[i], dataSet[p])<=eps]27 if len(N) >=minPts:28 #(6)創(chuàng)建個(gè)新簇C,并把p添加到C

29 #這里的C是一個(gè)標(biāo)記列表,直接對(duì)第p個(gè)結(jié)點(diǎn)進(jìn)行賦植

30 k += 1

31 C[p]=k32 #(7)令N為p的ε-鄰域中的對(duì)象的集合

33 #N是p的$\varepsilon$-鄰域點(diǎn)集合

34 #(8) for N中的每個(gè)點(diǎn)p'

35 for p1 inN:36 #(9) if p'是unvisited

37 if p1 invPoints.unvisitedlist:38 #(10)標(biāo)記p’為visited

39 vPoints.visit(p1)40 #(11) if p'的$\varepsilon$-鄰域至少有MinPts個(gè)點(diǎn),把這些點(diǎn)添加到N

41 #找出p'的$\varepsilon$-鄰域點(diǎn),并將這些點(diǎn)去重添加到N

42 M=[i for i in range(nPoints) ifdist(dataSet[i], \43 dataSet[p1]) <=eps]44 if len(M) >=minPts:45 for i inM:46 if i not inN:47 N.append(i)48 #(12) if p'還不是任何簇的成員,把P'添加到C

49 #C是標(biāo)記列表,直接把p'分到對(duì)應(yīng)的簇里即可

50 if C[p1] == -1:51 C[p1]=k52 #(15)else標(biāo)記p為噪聲

53 else:54 C[p]=-1

55

56 #(16)until沒(méi)有標(biāo)t己為unvisitedl內(nèi)對(duì)象

57 return C

利用sklearn生成數(shù)據(jù)集,共2500條數(shù)據(jù),并利用matplotlib畫(huà)出散點(diǎn)圖,代碼如下:

代碼3:生成數(shù)據(jù)集

1 importnumpy as np2 importmatplotlib.pyplot as plt3 from sklearn importdatasets4

5 X1, Y1 = datasets.make_circles(n_samples=2000, factor=0.6, noise=0.05,6 random_state=1)7 X2, Y2 = datasets.make_blobs(n_samples=500, n_features=2, centers=[[1.5,1.5]],8 cluster_std=[[0.1]], random_state=5)9

10 X =np.concatenate((X1, X2))11 plt.figure(figsize=(12, 9), dpi=80)12 plt.scatter(X[:,0], X[:,1], marker='.')13 plt.show()

圖2:數(shù)據(jù)集散點(diǎn)圖

設(shè)置參數(shù)Eps=0.1, MinPts=10,聚類(lèi)結(jié)果如下圖:

圖3:聚類(lèi)結(jié)果

3.?利用KD樹(shù)進(jìn)行優(yōu)化

KD樹(shù)(K-Dimensional Tree),是一種分割k維數(shù)據(jù)空間的數(shù)據(jù)結(jié)構(gòu),是二叉搜索樹(shù)在多維條件下的推廣。主要應(yīng)用于多維空間關(guān)鍵數(shù)據(jù)的搜索。KD樹(shù)的介紹見(jiàn):https://www.jianshu.com/p/ffe52db3e12b,不贅述。

利用scipy實(shí)現(xiàn)KD樹(shù)的構(gòu)造和查詢(xún),對(duì)代碼2的算法進(jìn)行改進(jìn),代碼如下:

代碼4:DBSCAN算法的優(yōu)化實(shí)現(xiàn)

1 importnumpy as np2 importmatplotlib.pyplot as plt3 importmath4 importrandom5 from scipy.spatial importKDTree6

7 def my-dbscan2(dataSet, eps, minPts):8 #numpy.ndarray的 shape屬性表示矩陣的行數(shù)與列數(shù)

9 #行數(shù)即表小所有點(diǎn)的個(gè)數(shù)

10 nPoints =dataSet.shape[0]11 #(1) 標(biāo)記所有對(duì)象為unvisited

12 #在這里用一個(gè)類(lèi)vPoints進(jìn)行實(shí)現(xiàn)

13 vPoints = visitlist(count=nPoints)14 #初始化簇標(biāo)記列表C,簇標(biāo)記為 k

15 k = -1

16 C = [-1 for i inrange(nPoints)]17 #構(gòu)建KD-Tree,并生成所有距離<=eps的點(diǎn)集合

18 kd =KDTree(X)19 while(vPoints.unvisitednum>0):20 #(3) 隨機(jī)選擇一個(gè)unvisited對(duì)象p

21 p =random.choice(vPoints.unvisitedlist)22 #(4) 標(biāo)t己p為visited

23 vPoints.visit(p)24 #(5) if p 的$\varepsilon$-鄰域至少有MinPts個(gè)對(duì)象

25 #N是p的$\varepsilon$-鄰域點(diǎn)列表

26 N =kd.query_ball_point(dataSet[p], eps)27 if len(N) >=minPts:28 #(6) 創(chuàng)建個(gè)一個(gè)新簇C,并把p添加到C

29 #這里的C是一個(gè)標(biāo)記列表,直接對(duì)第p個(gè)結(jié)點(diǎn)進(jìn)行賦值

30 k += 1

31 C[p] =k32 #(7) 令N為p的$\varepsilon$-鄰域中的對(duì)象的集合

33 #N是p的$\varepsilon$-鄰域點(diǎn)集合

34 #(8) for N中的每個(gè)點(diǎn)p'

35 for p1 inN:36 #(9) if p'是unvisited

37 if p1 invPoints.unvisitedlist:38 #(10) 標(biāo)記p'為visited

39 vPoints.visit(p1)40 #(11) if p'的$\varepsilon$-鄰域至少有MinPts個(gè)點(diǎn),把這些點(diǎn)添加到N

41 #找出p'的$\varepsilon$-鄰域點(diǎn),并將這些點(diǎn)去重新添加到N

42 M =kd.query_ball_point(dataSet[p1], eps)43 if len(M) >=minPts:44 for i inM:45 if i not inN:46 N.append(i)47 #(12) if p'還不是任何簇的成員,把p'添加到c

48 #C是標(biāo)記列表,直接把p'分到對(duì)應(yīng)的簇里即可

49 if C[p1] == -1

50 C[p1] =k51 #(15) else標(biāo)記p為噪聲

52 else:53 C[p1] = -1

54

55 #(16) until沒(méi)有標(biāo)記為unvisited的對(duì)象

56 return C

以代碼3中生成的2500條數(shù)據(jù)作為測(cè)試,比較優(yōu)化前后的算法性能

1 importtime2 start =time.time()3 C1 = my_dbscanl(X, 0.1, 10)4 end =time.time()5 print "`運(yùn)行時(shí)間`:", end -start6 plt.scatter(X[:, 0], X[:, 1], c=C1, marker='.')7 plt.show()8 >>> `運(yùn)行時(shí)間:`29.1249849796

圖4:優(yōu)化前算法結(jié)果

1 importtime2 start =time.time()3 C2 = my_dbscan2(X, 0.1, 10)4 end =time.time()5 print "運(yùn)行時(shí)間:", end -start6 plt.scatter(X[:, 0], X[:, 1], c=C2, marker='.')7 plt.show()8 >>> 運(yùn)行時(shí)間:4.72340583801

圖5:優(yōu)化后算法結(jié)果

可以看到優(yōu)化后的算法運(yùn)行時(shí)間從29.12s降到了4.72s,優(yōu)化的效果非常明顯。

4.?后記

上文僅僅是對(duì)DBSCAN算法的思想與實(shí)現(xiàn)進(jìn)行了簡(jiǎn)略摘要,是學(xué)習(xí)算法的一個(gè)過(guò)程。算法的學(xué)習(xí)還比較粗劣和淺層,在實(shí)踐應(yīng)用中上述代碼并不實(shí)用。如果需要使用DBSCAN的算法求解聚類(lèi)問(wèn)題,建議使用sklearn自帶的DBSCAN函數(shù)。以代碼3中生成數(shù)據(jù)為例:

1 #DBSCAN eps = 0.1, MinPts = 10

2 importtime3 from sklearn.cluster importDBSCAN4 start =time.time()5 C = DBSCAN(eps=0.1, min_pts=10).6 end =time.time()7 print "運(yùn)行時(shí)間:", end -start8 plt.scatter(X[:, 0], X[:, 1], c=C, marker='.')9 plt.show()10 >>> 運(yùn)行時(shí)間:0.0240921974182

總結(jié)

以上是生活随笔為你收集整理的dbscan算法python实现_挑子学习笔记:DBSCAN算法的python实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。