機器學習 聚類篇——python實作DBSCAN(基于密度的聚類方法)
- 摘要
- python實作代碼
- 計算實體
摘要
DBSCAN(Density-Based Spatial Clustering of Applications with Noise) 為一種基于密度的聚類演算法,它不僅可以找出具有任何形狀的簇,而且還可以用于檢測離群值,其基本思想為資料點分布緊湊的應被劃分為一類,而周圍未分布有或僅有極少數點的資料點則有可能為離群值,本文通過python實作了該聚類方法,并將代碼進行了封裝,方便讀者呼叫,
下圖為正文計算實體的可視化圖形,

python實作代碼
eps:鄰域半徑(float)
MinPts:密度閾值(int)
.fit(X):對待聚類的資料集進行聚類
用法:指定鄰域半徑和密度閾值,這兩個引數對應于不同的資料集需要進行調整,然后直接呼叫fit(X) 進行資料集的聚類,
# -*- coding: utf-8 -*-
# @Time : 2020/12/21 16:34
# @Author : CyrusMay WJ
# @FileName: cyrus_dbscan.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/Cyrus_May
import sys
import logging
import numpy as np
import random
class CyrusDBSCAN(object):
def __init__(self,eps=0.1,MinPts=3):
"""
:param eps: 鄰域半徑
:param MinPts: 密度閾值
"""
self.__build_logger()
self.eps = eps
self.MinPts = MinPts
def __build_logger(self):
self.logger = logging.getLogger()
self.logger.setLevel(logging.INFO)
screen_handler = logging.StreamHandler(sys.stdout)
screen_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(module)s.%(funcName)s:%(lineno)d - %(levelname)s - %(message)s')
screen_handler.setFormatter(formatter)
self.logger.addHandler(screen_handler)
def fit(self,X):
# 初始化資料點狀態及索引號
self.X = np.array(X)
global index,state,class_cluster
index = [i for i in np.arange(X.shape[0])]
state = [0] * X.shape[0]
class_cluster = 1
while 1:
if self.choice() is not None:
# 從未劃分的資料點中隨機選擇一個
point = self.choice()
# 計算在其領域半徑內的點
not_use_index = self.not_use_point()
temp = []
for i in not_use_index:
if i != point:
if self.cal_dist(self.X[i, :], self.X[point, :]) <= self.eps:
temp.append(i)
if len(temp) >= self.MinPts:
self.logger.info("搜索到第{}簇!".format(class_cluster))
self.cal_eps_count([point])
self.logger.info("第{}簇搜索完成!".format(class_cluster))
class_cluster += 1
else:
state[point] = "noise"
else:
break
return state
def cal_eps_count(self,points):
flag = []
for point in points:
temp = []
for i in self.not_use_point():
if self.cal_dist(self.X[i,:],self.X[point,:]) <= self.eps and i != point:
state[i] = class_cluster
temp.append(i)
self.logger.info("第{}簇新增一個資料點!".format(class_cluster))
if len(temp) >= self.MinPts:
flag += temp
if flag:
return self.cal_eps_count(flag)
def cal_dist(self,x1,x2):
return (((x1-x2)**2).sum())**0.5
def not_use_point(self):
temp = []
for i in index:
if state[i] in [0,"noise"]:
temp.append(i)
return temp
def choice(self):
temp = []
for i in index:
if state[i] == 0:
temp.append(i)
if len(temp) == 1:
state[temp[0]] = "noise"
return None
elif len(temp) == 0:
return None
else:
return random.choice(temp)
計算實體
對加入噪聲的月亮形狀資料集進行聚類
if __name__ == '__main__':
dbscan = CyrusDBSCAN(eps=0.25,MinPts=3)
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
moons = make_moons(n_samples=1000,noise=0.05)
y = dbscan.fit(moons[0])
dbscan.logger.info(y)
plt.scatter(moons[0][:, 0], moons[0][:, 1], c=[["r", "b"][i-1] if i != "noise" else "g" for i in y])
plt.show()
2020-12-21 21:14:32,952 - cyrus_dbscan.cal_eps_count:68 - INFO - 第2簇新增一個資料點!
2020-12-21 21:14:32,952 - cyrus_dbscan.cal_eps_count:68 - INFO - 第2簇新增一個資料點!
2020-12-21 21:14:32,955 - cyrus_dbscan.fit:53 - INFO - 第2簇搜索完成!
2020-12-21 21:14:32,956 - cyrus_dbscan.<module>:103 - INFO - [1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2]

by CyrusMay 2020 12 21
我沒有任何天分
我卻有夢的天真
我是傻 不是蠢
我將會證明
用我的一生
——————五月天(咸魚)——————
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/238562.html
標籤:python
