데이터 마이닝 자바 - DBSCAN 알고리즘 구현

1. DBSCAN 알고리즘에 대한 사전 지식

DBSCAN 알고리즘 : 포인트 q의 영역에 MinPts 개체보다 많은 개체가 포함된 경우 q를 코어 개체로 하는 클러스터를 만듭니다. 그런 다음 이러한 핵심 개체에서 직접 밀도에 도달할 수 있는 개체를 반복적으로 찾고 일부 밀도에 도달할 수 있는 클러스터를 병합합니다. 클러스터에 새 포인트를 추가할 수 없으면 프로세스가 종료됩니다.

DBSCAN 은 대표적인 밀도 기반 클러스터링 알고리즘 입니다 . 분할 및 계층적 군집화 방식과 달리 군집을 밀도가 연결된 점들의 가장 큰 집합으로 정의하고, 밀도가 충분히 높은 영역을 군집으로 분할할 수 있으며, "노이즈"가 있는 공간 데이터베이스에서 임의의 모양의 군집을 찾을 수 있는 종류입니다. 클러스터링은 데이터 개체를 여러 클래스 또는 클러스터로 그룹화하는 것입니다. 분할 원칙은 동일한 클러스터에 있는 개체는 높은 유사성을 갖는 반면 다른 클러스터에 있는 개체는 상당히 다르다는 것입니다. 분류와 달리 군집화 작업에서 나눌 클래스는 미리 알 수 없으며, 클래스의 구성은 완전히 데이터 기반으로 이루어지며 비지도 학습 방식에 속합니다.

물체의 ε-영역 : 주어진 물체의 반지름 ε 내의 면적.

코어 객체 : 객체의 ε-필드에 최소 개수의 MinPts 객체가 포함되어 있으면 해당 객체를 코어 객체라고 합니다.

직접 밀도 도달 가능성 : 개체 집합 D가 주어지면 p가 q의 ε 필드에 있고 q가 핵심 개체인 경우 개체 p는 개체 q에서 직접 도달할 수 있는 밀도라고 합니다.
Density-connected: 개체 집합 D에 개체 o가 존재하여 개체 p와 q가 ε 및 MinPts에 대해 o에서 밀도 도달 가능하면 개체 p와 q는 ε 및 MinPts에 대해 밀도 연결됩니다.

2. DBSCAN 알고리즘의 기본 아이디어

DBSCAN은 대표적인 밀도 기반 클러스터링 알고리즘입니다. 분할 및 계층적 군집화 방식과 달리 군집을 밀도가 연결된 점들의 가장 큰 집합으로 정의하고, 밀도가 충분히 높은 영역을 군집으로 분할할 수 있으며, "노이즈"가 있는 공간 데이터베이스에서 임의의 모양의 군집을 찾을 수 있는 종류입니다.
데이터베이스에서 미가공 포인트 추출, 추출된 포인트가 코어 포인트인 경우 포인트 밀도에서 도달 가능한 모든 객체를 찾아 클러스터 형성, 추출된 포인트가 에지 포인트(비코어 객체)인 경우 점프 아웃 이 루프는 모든 포인트가 처리될 때까지 다음 포인트를 찾습니다.

3. DBSCAN 알고리즘의 예

DBSCAN 알고리즘 예제
여기에 이미지 설명 삽입
여기에 이미지 설명 삽입

4. DBSCAN 알고리즘 구현 과정

실험 내용
다음과 같은 2차원 데이터 세트가 있습니다. ε = 2, minpts = 3, DBSCAN 알고리즘을 사용하여 클러스터링하십시오(Manhattan 거리 사용). 실험 아이디어 (1) 가로 좌표 x를 포함하는 Point 클래스
여기에 이미지 설명 삽입
정의
좌표 y 및 정적 메서드를 포함한 기타 속성 getIsSame(): 두 개의 Point 개체가 동일한지 여부를 확인,calculateDistance() 메서드: 두 개의 Point 개체 사이의 거리(유클리드 거리) 계산,calculateMHDDistance() 메서드: 두 개의 Point 개체 계산 클래스 개체 간의 거리(맨해튼 거리). ExcelData 클래스 정의 ExcelData 클래스는 가로 x(추가 주석 @ExcelProperty(value="abscissa")) 및 세로 좌표 y(추가 주석 @ExcelProperty(value="ordinate"))를 포함하며 ExcelData 클래스가 주로 사용됩니다. 읽기용 엑셀 파일의 데이터를 가져와 ExcelData 클래스에 매핑합니다. 속성 코어 포인트 corePoint 및 클러스터 sameList의 모든 포인트 콜렉션을 포함하는 클러스터 클래스를 정의하십시오.
(2) 초기 데이터 세트 dataList를 정의하고 반경 e를 정의하고 코어 객체 e의 필드에 있는 객체의 최소 개수 MinPts를 정의하고 getFileData() 메서드를 호출하여 초기 데이터 세트를 초기화합니다. getFileData() 메서드 본문 내에서 EasyExcel을 사용하여 Excel 파일을 읽고 ExcelData 클래스 개체에 매핑하고, ExcelData 클래스 개체의 속성 x 및 속성 y를 구성 매개변수로 사용하고, Point 클래스 개체 포인트를 인스턴스화하고, 모두 변환합니다. 데이터 세트의 초기화를 완료하기 위해 dataList 컬렉션에 포인트가 추가됩니다.
(3) 모든 클러스터를 저장할 clusterList 컬렉션을 만듭니다. dataList 컬렉션의 각 Point 클래스 개체 포인트를 탐색합니다. 루프 본문 내에서 getEPointList() 메서드를 호출하여 Point 클래스 개체의 필드에서 모든 포인트 컬렉션 ePointList를 가져옵니다. ePointList 컬렉션의 길이가 MinPts보다 작지 않으면, 이것은 포인트 포인트가 코어 객체라는 것을 의미합니다. 그런 다음 포인트를 코어 객체로 사용하여 클러스터를 인스턴스화하고 ePointList를 사용하여 클러스터의 sameList 속성을 인스턴스화한 다음 canReachPoint() 메서드를 호출하여 밀도에 도달할 수 있는 포인트를 직접 통과합니다. 핵심 개체, 모든 밀도 도달 가능 지점 병합 및 최종 클러스터 newCluster가 클러스터 세트 newCluster에 추가됩니다. 루프 본문 내에서 먼저 isExitCluster() 메서드를 호출하여 포인트가 특정 클러스터에 이미 존재하는지 확인하고 클러스터에 이미 있는 포인트는 고려하지 않으며 루프 본문의 다음 코드는 실행되지 않으며, 다음 주기는 dataList 컬렉션의 각 항목을 순회한 후 루프가 종료될 때까지 직접 순회됩니다.
(4) clustrList 컬렉션을 트래버스하고 컬렉션의 각 항목 클러스터를 출력합니다.
(5) isExistCluster() 메서드 본문에서 포인트 객체가 기존 클러스터에 이미 있는지 여부를 판단하고, clusterList 컬렉션의 각 클러스터를 탐색하고, 클러스터 클러스터의 sameList 속성을 획득하고, sameList 컬렉션에 포인트가 포함되어 있는지 여부를 판단합니다. , 포함된 경우 true를 반환합니다. 순회 후 false를 반환합니다.
(6) canReachPoint() 메소드의 몸체 내부에서 클러스터에 포함된 모든 포인트를 순회하여 코어 오브젝트 포인트를 제외한 각 포인트가 코어 오브젝트인지 여부를 판단합니다. 도메인은 클러스터 코어 포인트의 밀도 도달 가능 포인트도 클러스터 클러스터에 병합될 수 있으며, 이러한 포인트는 밀도 도달 가능 포인트 세트 reachPointList에 추가됩니다.루프가 끝나면 세트의 모든 밀도 도달 가능 포인트는 reachPointList가 추가되었습니다.클러스터의 sameList 컬렉션으로 이동하여 클러스터를 다시 인스턴스화하고 마지막으로 클러스터를 반환합니다.
(7) getEpointList() 메소드의 기능은 포인트 e의 필드에 있는 모든 포인트의 집합을 얻는 것입니다. 메소드 본문 내에서 포인트 세트 pointList를 정의하여 포인트의 e 필드에 모든 포인트를 저장하고, 데이터 세트 dataList의 각 포인트 p를 순회하고, Point 클래스에서 정적 메소드 calculateMHDDistance() 메소드를 호출하여 포인트 포인트와 포인트를 계산합니다. ptoPoint라는 변수에 ptoPoint가 저장되어 있는데 ptoPoint가 반지름 e보다 작으면 p가 point의 e필드에 있다는 것을 의미하고 p가 pointList 컬렉션에 추가되고 마지막으로 pointList 컬렉션이 반환됩니다.

소스 코드를 실현

Cluster类
package com.data.mining.entity;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class Cluster {
    
    
    private Point corePoint;
    private List<Point> sameList = new ArrayList<>();

    public Cluster(){
    
    }

    public Cluster(Point cp){
    
    
        corePoint = cp;
    }
}

Point类
package com.data.mining.entity;

import lombok.Data;

@Data
public class Point {
    
    
    private double x;
    private double y;

    public Point(){
    
    }

    public Point(double x, double y){
    
    
        this.x = x;
        this.y = y;
    }

    public static boolean getIsSame(Point p1, Point p2){
    
    
        if (p1.getX() == p2.getX() && p1.getY() == p2.getY()) return true;
        return false;
    }

    public static double calculateDistance(Point p1, Point p2){
    
    
        double xDistance = p1.getX() - p2.getX();
        double yDistance = p1.getY() - p2.getY();
        double tmp = xDistance * xDistance + yDistance * yDistance;
        return Math.sqrt(tmp);
    }

    public static double calculateMHDDistance(Point p1, Point p2){
    
    
        return Math.abs(p1.getX() - p2.getX()) + Math.abs(p1.getY() - p2.getY());
    }

}

ExcelData类:因为本实验样本集太多,于是笔者将样本集存入到了excel文件中,用EasyExcel读取excel文件。因此创建ExcelData类
package com.data.mining.entity;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class Cluster {
    
    
    private Point corePoint;
    private List<Point> sameList = new ArrayList<>();

    public Cluster(){
    
    }

    public Cluster(Point cp){
    
    
        corePoint = cp;
    }
}

DBSCAN算法实现代码
package com.data.mining.main;

import com.alibaba.excel.EasyExcel;
import com.data.mining.entity.Cluster;
import com.data.mining.entity.ExcelData;
import com.data.mining.entity.Point;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

public class DBSCAN {
    
    
    // 定义初始数据集
    public static List<Point> dataList = new ArrayList<>();
    // 定义半径e
    public static double e = 2.0;
    // 定义核心对象领域内对象的最少数目
    public static int MinPts = 3;

    public static void main(String[] args) {
    
    
        getFileData();
//        initDataList();
        List<Cluster> clusterList = new ArrayList<>();
        for (Point point : dataList) {
    
    
            if (isExistCluster(point, clusterList)) continue; //已经在簇中的点不再考虑
            List<Point> ePointList = getEPointList(point);
            if (ePointList.size() >= MinPts){
    
     //说明点point是核心对象
                Cluster cluster = new Cluster(point);
                cluster.setSameList(ePointList);
                Cluster newCluster = canReachPoint(cluster);
                clusterList.add(newCluster);
            }
        }
        int pointSum = 0;
        for (Cluster cluster : clusterList) {
    
    
            System.out.println(cluster);
            pointSum += cluster.getSameList().size();
        }
        System.out.println(pointSum);
    }

    /**
     * 判断point是否已经在已存在的簇中
     * @param point
     * @param clusterList
     * @return
     */
    public static boolean isExistCluster(Point point, List<Cluster> clusterList){
    
    
        for (Cluster cluster : clusterList) {
    
    
            List<Point> pointList = cluster.getSameList();
            if (pointList.contains(point)) return true;
        }
        return false;
    }

    /**
     * 遍历核心对象直接密度可达的点,合并其所有密度可达的点
     * @param cluster
     * @return
     */
    public static Cluster canReachPoint(Cluster cluster){
    
    
        List<Point> pointList = cluster.getSameList();
        List<Point> reachPointList = new ArrayList<>(); //存放核心点所有密度可达的点(暂存要新加入进来的点)
        for (Point point : pointList) {
    
    
            Point corePoint = cluster.getCorePoint();
            if (Point.getIsSame(corePoint, point)) continue; //这里不再遍历核心对象点
            List<Point> reachList = getEPointList(point); //核心对象直接密度可达的点其e领域内所有的点的集合
            if (reachList.size() >= MinPts){
    
     //说明point也是核心对象,其领域内的所有点也可以合并到cluster中
                for (Point reachPoint : reachList) {
    
    
                    if (pointList.contains(reachPoint)) continue; //对于pointList中已经有的点不再重复添加
                    reachPointList.add(reachPoint); //将密度可达的点添加到密度可达的点集合中
                }
            }
        }
        pointList.addAll(reachPointList); //将密度可达的点全加入到簇中
        cluster.setSameList(pointList);
        return cluster;
    }

    /**
     * 获取一个点的e领域内所有的点集合
     * @param point
     * @return
     */
    public static List<Point> getEPointList(Point point){
    
    
        List<Point> pointList = new ArrayList<>(); //存放point的e领域内所有的点
        for (Point p : dataList) {
    
    
            double ptoPoint = Point.calculateMHDDistance(point, p);
            if (ptoPoint <= e) pointList.add(p); //说明点p在point的e领域内
        }
        return pointList;
    }

    public static void getFileData(){
    
    
        try {
    
    
            FileInputStream inputStream = new FileInputStream("E:\\宋泽旭个人\\课程作业\\课程设计\\data_mining\\dbscan.xlsx");

            List<ExcelData> fileData = EasyExcel.read(inputStream).head(ExcelData.class).sheet()
                    .headRowNumber(1).doReadSync();
            for (ExcelData excelData : fileData) {
    
    
                Point point = new Point(excelData.getX(), excelData.getY());
                dataList.add(point);
            }
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }
    /**
     * 使用了书本上的例子进行测试,只为测试算法实现是否正确。main方法中并没有执行initDataList方法
     */
    public static void initDataList(){
    
    
        Point p1 = new Point(1, 0);
        Point p2 = new Point(4, 0);
        Point p3 = new Point(0, 1);
        Point p4 = new Point(1, 1);
        Point p5 = new Point(2, 1);
        Point p6 = new Point(3, 1);
        Point p7 = new Point(4, 1);
        Point p8 = new Point(5, 1);
        Point p9 = new Point(0, 2);
        Point p10 = new Point(1, 2);
        Point p11 = new Point(4, 2);
        Point p12 = new Point(1, 3);

        dataList.add(p1);
        dataList.add(p2);
        dataList.add(p3);
        dataList.add(p4);
        dataList.add(p5);
        dataList.add(p6);
        dataList.add(p7);
        dataList.add(p8);
        dataList.add(p9);
        dataList.add(p10);
        dataList.add(p11);
        dataList.add(p12);
    }
}


실험 결과
여기에 이미지 설명 삽입
사진이 너무 작아서 잘 안보여서 표로 보여줍니다.
여기에 이미지 설명 삽입

5. 실험 요약

저자는 이 실험의 결과가 정확하다는 것을 보증하지 않으며 자바 언어를 사용하여 DBSCAN 알고리즘을 구현하는 방법을 제공할 뿐입니다. 실험이 답을 주지 않았기 때문에 작성자는 인터넷에 답이 있는 실험 데이터를 프로그램에 입력했고 프로그램에서 출력되는 결과는 답과 일치하므로 문제가 크지 않아야 합니다. 잘 작성되지 않은 내용이 있으면 몇 가지 조언을 해주세요!
저자의 홈페이지에는 다른 데이터 마이닝 알고리즘에 대한 요약도 있습니다. 후원을 환영합니다!

Supongo que te gusta

Origin blog.csdn.net/qq_54162207/article/details/128366377
Recomendado
Clasificación