用戶地理位置的聚類算法實現(xiàn)—基于DBSCAN和Kmeans的混合算法

1. 聚類算法簡介

聚類的目標是使同一類對象的相似度盡可能地大楼雹;不同類對象之間的相似度盡可能地小脐雪。目前聚類的方法很多详幽,根據(jù)基本思想的不同筛欢,大致可以將聚類算法分為五大類:層次聚類算法、分割聚類算法唇聘、基于約束的聚類算法版姑、機器學(xué)習(xí)中的聚類算法和用于高維度的聚類算法。

以下實現(xiàn)主要選取了基于劃分的Kmeans算法和基于密度的DBSCAN算法來處理

1.1 基于劃分的Kmeans算法

一種典型的劃分聚類算法迟郎,它用一個聚類的中心來代表一個簇剥险,即在迭代過程中選擇的聚點不一定是聚類中的一個點。其目的是使各個簇(共k個)中的數(shù)據(jù)點與所在簇質(zhì)心的誤差平方和SSE(Sum of Squared Error)達到最小宪肖,這也是評價K-means算法最后聚類效果的評價標準表制。

算法的詳細原理可自行Google或Wiki。

1.2 基于密度的DBSCAN算法

一種典型的基于密度的聚類算法控乾,該算法采用空間索引技術(shù)來搜索對象的鄰域么介,引入了“核心對象”和“密度可達”等概念,從核心對象出發(fā)阱持,把所有密度可達的對象組成一個簇。簡單的說就是根據(jù)一個根據(jù)對象的密度不斷擴展的過程的算法魔熏。一個對象O的密度可以用靠近O的對象數(shù)來判斷衷咽。

在DBSCAN算法中將數(shù)據(jù)點分為一下三類:

核心點:在半徑Eps內(nèi)含有超過MinPts數(shù)目的點

邊界點:在半徑Eps內(nèi)點的數(shù)量小于MinPts,但是落在核心點的鄰域內(nèi)

噪音點:既不是核心點也不是邊界點的點

這里有兩個量蒜绽,一個是半徑Eps镶骗,另一個是指定的數(shù)目MinPts。

2. 用戶地理位置信息的的聚類實現(xiàn)

本實驗用Python實現(xiàn)躲雅,依賴numpy, pandas, sklearn, scipy等科學(xué)計算library鼎姊。

數(shù)據(jù)來自收集得到的用戶的地理位置信息,即經(jīng)緯度數(shù)據(jù)的序列集。

xy = numpy.array([[116.455788, 39.920767], [116.456065, 39.920965], [116.452312, 39.92304], [116.421385, 39.989539],

[116.455685, 39.92069], [116.455876, 39.920845], [116.455973, 39.920902], [116.455645, 39.920657],

[116.456022, 39.920934], [116.455685, 39.920691], [116.456023, 39.920671], [116.45596, 39.920864],

[116.455522, 39.920856], [116.455276, 39.920407], [116.455799, 39.920867],

[116.455349, 39.920425], [116.45511, 39.920377], [116.455318, 39.920442], [116.455298, 39.920474],

[116.455839, 39.920636], [116.455979, 39.921168], [116.454281, 39.920006], [116.45598, 39.920612],

[116.45388, 39.919584], [116.455474, 39.920737], [116.456009, 39.920641], [116.455439, 39.920574],

[116.455759, 39.920841], [116.455838, 39.920644], [116.455983, 39.920847],

[116.459803, 39.922041], [116.456029, 39.92088], [116.455539, 39.920603], [116.455989, 39.920851],

[116.455719, 39.920789], [116.45601, 39.92082], [116.456229, 39.920564], [116.455906, 39.920771],

[116.456248, 39.920868], [116.455805, 39.920544], [116.455896, 39.920758], [116.43692, 39.926767],

[116.454672, 39.92024], [116.454813, 39.917848], [116.381415, 40.00875], [116.422925, 39.980757],

[116.422849, 39.9808], [116.38107, 40.009217], [116.456078, 39.920747], [116.455242, 39.919515],

[116.455615, 39.920533], [116.422092, 39.991104], [116.454847, 39.917724],

[116.456686, 39.924316], [116.45575, 39.920642], [116.456713, 39.924413], [116.455846, 39.920828],

[116.422108, 39.991098], [116.422075, 39.991139], [118.775572, 31.97337], [118.776968, 31.97392],

[118.778187, 31.973121], [118.775695, 31.973254], [118.775302, 31.973807],

[118.776303, 31.973692], [118.777541, 31.973439], [118.776196, 31.973489],

[116.448944, 39.926799], [116.45487, 39.917804], [116.455762, 39.920645], [116.456146, 39.920441],

[116.455857, 39.920043], [116.455458, 39.920826], [116.455533, 39.920791],

[116.455426, 39.920896], [116.45566, 39.920811], [116.455696, 39.920621], [116.453667, 39.9259],

[116.466606, 39.886322], [116.455917, 39.92062]])

2.1 基于Kmeans的聚類實現(xiàn)

假設(shè)用戶的地理位置信息通常是工作地點和家相寇,因此選取k值為2慰于,代碼如下

res, idx = kmeans2(numpy.array(zip(xy[:, 0], xy[:, 1], z)), 2, iter=20, minit='points')

實現(xiàn)輸出結(jié)果

但是實際上用戶并未在河北出現(xiàn)過,用戶經(jīng)常出現(xiàn)的地方除了北京的工作地方和家唤衫,還曾經(jīng)在南京出差一段時間婆赠。所以將K值設(shè)定為3,再次運行

res, idx = kmeans2(numpy.array(zip(xy[:, 0], xy[:, 1], z)), 3, iter=20, minit='points')

輸出結(jié)果

這樣就將南京的地理位置區(qū)分出來了佳励。工作地方和出差地方已經(jīng)非常貼合了休里,但是家的地方離實際距離還是差了不少距離。

其實已經(jīng)可以看出來赃承,由于用戶的出現(xiàn)地點不可預(yù)知妙黍,因此很難確定K值。并且Kmeans聚合得到的結(jié)果取得是聚合簇的質(zhì)心位置瞧剖,并不是用戶的實際地理位置拭嫁,而且我選取的是相似度量是歐式距離,而不是經(jīng)緯度計算的球面距離筒繁。因此得到的結(jié)果并不理想噩凹。

2.2 基于DBSCAN的聚類實現(xiàn)

DBSCAN算法的重點是選取的聚合半徑參數(shù)和聚合所需指定的MinPts數(shù)目。

在此使用球面距離來衡量地理位置的距離毡咏,來作為聚合的半徑參數(shù)驮宴。

如下實驗,選取2公里作為密度聚合的半徑參數(shù)呕缭,MinPts個數(shù)為5.

def haversine(lonlat1, lonlat2):

lat1, lon1 = lonlat1

lat2, lon2 = lonlat2

lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

dlon = lon2 - lon1

dlat = lat2 - lat1

a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2

c = 2 * asin(sqrt(a))

r = 6371? # Radius of earth in kilometers. Use 3956 for miles

return c * r

def clustering_by_dbscan():

......

distance_matrix = squareform(pdist(X, (lambda u, v: haversine(u, v))))

db = DBSCAN(eps=2, min_samples=5, metric='precomputed')

y_db = db.fit_predict(distance_matrix)

X['cluster'] = y_db

......

plt.scatter(X['lat'], X['lng'], c=X['cluster'])

plt.show()

輸出如下

結(jié)果顯示該用戶的地理位置信息聚合簇為4塊堵泽,在結(jié)果中分別用0.0,1.0,2.0恢总,-1.0來標記迎罗。可以看出DBSCAN算法可以根據(jù)用戶的活動半徑片仿,也就是設(shè)定的最小半徑參數(shù)2公里纹安,將用戶的活動地理位置數(shù)據(jù)集合分為了4簇,而且每一簇在空間上都是任意形狀的砂豌,分類聚合的效果是不錯的厢岂,但是得到的結(jié)果是一個個的簇,也就是一個個的地理點的集合阳距,并不是一個“中心”塔粒。并且存在的噪聲點無法區(qū)分。

3.基于DBSCAN和Kmeans的混合算法實現(xiàn)

從上面的實驗結(jié)果筐摘,Kmeans算法的關(guān)鍵的是 K值的選取卒茬,而我無法確定用戶地理信息聚類的簇的個數(shù)船老,如果實際上的地理位置的分布過于分散,按照固定K值聚合圃酵,得到的質(zhì)心的位置可能和實際位置相差甚遠柳畔。而DBSCAN的算法,聚類結(jié)果不錯辜昵,因為是按照設(shè)定的人的活動半徑的密度可達來聚合的荸镊,但其結(jié)果是將數(shù)據(jù)集合分類,并不求出中心點堪置。

因此我設(shè)計了一種基于DBSCAN和Kmeans的混合算法:先利用DBSCAN算法的密度可達特性將用戶的地理位置數(shù)據(jù)集按照活動半徑聚合成若干個簇躬存,并且將每一簇的數(shù)據(jù)集作為新的輸入,再利用Kmeans算法的迭代聚合求出質(zhì)心的位置舀锨,設(shè)定K值為1岭洲。

代碼如下

def clustering_by_dbscan_and_kmeans2():

X = pd.DataFrame(

{"lat": [39.920767, 39.920965, 39.92304, 39.989539, 39.92069, 39.920845, 39.920902, 39.920657, 39.920934,

39.920691, 39.920671, 39.920864, 39.920856, 39.920407, 39.920867, 39.920425, 39.920377, 39.920442,

39.920474, 39.920636, 39.921168, 39.920006, 39.920612, 39.919584, 39.920737, 39.920641, 39.920574,

39.920841, 39.920644, 39.920847, 39.922041, 39.92088, 39.920603, 39.920851, 39.920789, 39.92082,

39.920564, 39.920771, 39.920868, 39.920544, 39.920758, 39.926767, 39.92024, 39.917848, 40.00875,

39.980757, 39.9808, 40.009217, 39.920747, 39.919515, 39.920533, 39.991104, 39.917724, 39.924316,

39.920642, 39.924413, 39.920828, 39.991098, 39.991139, 31.97337, 31.97392, 31.973121, 31.973254,

31.973807, 31.973692, 31.973439, 31.973489, 39.926799, 39.917804, 39.920645, 39.920441, 39.920043,

39.920826, 39.920791, 39.920896, 39.920811, 39.920621, 39.9259, 39.886322, 39.92062],

"lng": [116.455788, 116.456065, 116.452312, 116.421385, 116.455685, 116.455876, 116.455973, 116.455645,

116.456022, 116.455685, 116.456023, 116.45596, 116.455522, 116.455276, 116.455799, 116.455349,

116.45511, 116.455318, 116.455298, 116.455839, 116.455979, 116.454281, 116.45598, 116.45388,

116.455474, 116.456009, 116.455439, 116.455759, 116.455838, 116.455983, 116.459803, 116.456029,

116.455539, 116.455989, 116.455719, 116.45601, 116.456229, 116.455906, 116.456248, 116.455805,

116.455896, 116.43692, 116.454672, 116.454813, 116.381415, 116.422925, 116.422849, 116.38107,

116.456078, 116.455242, 116.455615, 116.422092, 116.454847, 116.456686, 116.45575, 116.456713,

116.455846, 116.422108, 116.422075, 118.775572, 118.776968, 118.778187, 118.775695, 118.775302,

118.776303, 118.777541, 118.776196, 116.448944, 116.45487, 116.455762, 116.456146, 116.455857,

116.455458, 116.455533, 116.455426, 116.45566, 116.455696, 116.453667, 116.466606, 116.455917]

})

distance_matrix = squareform(pdist(X, (lambda u, v: haversine(u, v))))

db = DBSCAN(eps=2, min_samples=5, metric='precomputed')

y_db = db.fit_predict(distance_matrix)

X['cluster'] = y_db

results = {}

for i in X.values:

if i[2] not in results.keys():

results[i[2]] = [[i[1], i[0]]]

else:

if results[i[2]]:

results[i[2]].append([i[1], i[0]])

else:

results[i[2]] = [[i[1], i[0]]]

print "DBSCAN output: ", len(results), results.keys()

print "KMeans calc center as below: "

for k in results.keys():

xy = numpy.array(results[k])

z = numpy.sin(xy[:, 1] - 0.2 * xy[:, 1])

z = whiten(z)

res, idx = kmeans2(numpy.array(zip(xy[:, 0], xy[:, 1], z)), 1, iter=20, minit='points')

address_text = my_get_address_text_by_location(res[0][1], res[0][0])

print res, address_text

輸出如下

其中”家“,”公司“坎匿,”出差“的位置信息已經(jīng)非常貼合用戶的實際信息了盾剩。

但是仍然存在的噪聲點的信息。這個暫時還沒找到解決方案替蔬,下一步的思路是帶入用戶地理位置信息收集時候得到的附屬信息如時間來輔助分析告私,希望可以有更好的結(jié)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末承桥,一起剝皮案震驚了整個濱河市驻粟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凶异,老刑警劉巖蜀撑,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異剩彬,居然都是意外死亡酷麦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門喉恋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沃饶,“玉大人,你說我怎么就攤上這事轻黑『簦” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵苔悦,是天一觀的道長轩褐。 經(jīng)常有香客問我椎咧,道長玖详,這世上最難降的妖魔是什么把介? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蟋座,結(jié)果婚禮上拗踢,老公的妹妹穿的比我還像新娘。我一直安慰自己向臀,他們只是感情好巢墅,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著券膀,像睡著了一般君纫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芹彬,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天蓄髓,我揣著相機與錄音,去河邊找鬼舒帮。 笑死会喝,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的玩郊。 我是一名探鬼主播肢执,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼译红!你這毒婦竟也來了预茄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤临庇,失蹤者是張志新(化名)和其女友劉穎反璃,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體假夺,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡淮蜈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了已卷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梧田。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖侧蘸,靈堂內(nèi)的尸體忽然破棺而出裁眯,到底是詐尸還是另有隱情,我是刑警寧澤讳癌,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布穿稳,位于F島的核電站,受9級特大地震影響晌坤,放射性物質(zhì)發(fā)生泄漏逢艘。R本人自食惡果不足惜旦袋,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望它改。 院中可真熱鬧疤孕,春花似錦、人聲如沸央拖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲜戒。三九已至专控,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間遏餐,已是汗流浹背踩官。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留境输,地道東北人蔗牡。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像嗅剖,于是被迫代替她去往敵國和親辩越。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容