データ マイニング Java - DBSCAN アルゴリズムの実装

1. DBSCAN アルゴリズムの予備知識

DBSCAN アルゴリズム: 点 q の領域に MinPts 個以上のオブジェクトが含まれる場合、q をコア オブジェクトとしてクラスターを作成します。次に、これらのコア オブジェクトから直接密度到達可能なオブジェクトを繰り返し見つけ、いくつかの密度到達可能なクラスターをマージします。どのクラスターにも新しいポイントを追加できなくなると、プロセスは終了します。

DBSCAN は、代表的な密度ベースのクラスタリング アルゴリズムです。パーティショニングや階層クラスタリング手法とは異なり、密度で接続された点の最大の集合としてクラスターを定義し、十分に高密度の領域をクラスターに分割し、「ノイズの多い」空間データベースで任意の形状のクラスターを見つけることができます。クラスタリングとは、データ オブジェクトを複数のクラスまたはクラスターにグループ化することです。分割の原理は、同じクラスター内のオブジェクトは高度な類似性を持ち、異なるクラスター内のオブジェクトはまったく異なるということです。分類とは異なり、クラスタリング操作で分割されるクラスは事前に不明であり、クラスの形成は完全にデータ駆動型であり、教師なし学習手法に属します。

オブジェクトの ε 領域: 指定されたオブジェクトの半径 ε 内の領域。

コア オブジェクト: オブジェクトの ε フィールドに少なくとも最小数の MinPts オブジェクトが含まれる場合、そのオブジェクトはコア オブジェクトと呼ばれます。

直接密度到達可能性: オブジェクトの集合 D が与えられ、p が q の ε フィールド内にあり、q がコア オブジェクトである場合、オブジェクト p はオブジェクト q から直接密度到達可能であると言います。
密度接続: オブジェクト p と q が ε と MinPts に関して o から密度到達可能であるオブジェクト集合 D にオブジェクト o が存在する場合、オブジェクト p と q は ε と MinPts に関して密度接続されます。

2. DBSCANアルゴリズムの基本的な考え方

DBSCAN は、代表的な密度ベースのクラスタリング アルゴリズムです。パーティショニングや階層クラスタリング手法とは異なり、密度で接続された点の最大の集合としてクラスターを定義し、十分に高密度の領域をクラスターに分割し、「ノイズの多い」空間データベースで任意の形状のクラスターを見つけることができます。
データベースから未処理の点を抽出し、抽出した点がコア点の場合は点密度から到達可能なすべてのオブジェクトを見つけてクラスタを形成し、抽出された点がエッジ点(非コアオブジェクト)の場合は飛び出すこのループでは、すべてのポイントが処理されるまで次のポイントを探します。

3. DBSCAN アルゴリズムの例

DBSCAN アルゴリズムの例
ここに画像の説明を挿入
ここに画像の説明を挿入

4. DBSCANアルゴリズムの実装プロセス

実験内容
次の 2 次元データセットがあります。ε = 2、minpts = 3 として、DBSCAN アルゴリズムを使用してクラスター化してください (マンハッタン距離を使用) 実験アイデア (1) 横軸 x を含む Point クラスを定義します
ここに画像の説明を挿入

縦座標 y および静的メソッドを含むその他の属性 getIsSame(): 2 つの Point オブジェクトが同じかどうかを判断する、calculateDistance() メソッド: 2 つの Point オブジェクト間の距離 (ユークリッド距離) を計算する、calculateMHDDistance() メソッド: 2 つの Point オブジェクトを計算するクラス オブジェクト間の距離 (マンハッタン距離)。ExcelData クラスを定義します。ExcelData クラスには、横座標 x (注釈 @ExcelProperty(value="abscissa") を追加) と縦座標 y (注釈 @ExcelProperty(value="座標") を追加します。主に ExcelData クラスが使用されます読み取り用 Excel ファイルのデータを取得し、ExcelData クラスにマッピングします。属性コア ポイント corePoint とクラスター SameList 内のすべてのポイントのコレクションを含む Cluster クラスを定義します。
(2)初期データセットdataListを定義し、半径eを定義し、コアオブジェクトeのフィールド内のオブジェクトの最小数MinPtsを定義し、getFileData()メソッドを呼び出して初期データセットを初期化する。getFileData() メソッド本体内で、EasyExcel を使用して Excel ファイルを読み取り、それを ExcelData クラス オブジェクトにマップし、ExcelData クラス オブジェクトの属性 x と属性 y を構築パラメータとして使用し、Point クラス オブジェクトのポイントをインスタンス化し、すべてを変換します。ポイントが dataList コレクションに追加され、データ セットの初期化が完了します。
(3) すべてのクラスターを格納するために、clusterList コレクションを作成します。dataList コレクション内の各 Point クラス オブジェクト ポイントを走査します。ループ本体内で、getEPointList() メソッドを呼び出して、Point クラス オブジェクトのフィールド内のすべてのポイント コレクション ePointList を取得します。ePointList コレクションの長さが MinPts 以上の場合、これは、ポイント point がコア オブジェクトであることを意味します。次に、ポイントをコア オブジェクトとしてクラスターをインスタンス化し、ePointList を使用してクラスターの SameList プロパティをインスタンス化し、canReachPoint() メソッドを呼び出して、密度が直接到達可能なポイントを横断します。コア オブジェクトを作成し、その密度到達可能なポイントをすべてマージし、最後のクラスター newCluster がクラスター セット newCluster に追加されます。ループ本体内で、まず isExitCluster() メソッドを呼び出して、ポイントが特定のクラスターに既に存在するかどうかを判断します。クラスター内に既に存在するポイントは考慮されず、ループ本体内の次のコードは実行されません。次のサイクルは、dataList コレクション内の各項目を走査した後、ループが終了するまで直接走査されます。
(4) clusetrList コレクションを走査し、コレクション内の各項目クラスターを出力します。
(5) isExistCluster()メソッドの本体では、ポイントオブジェクトが既存のクラスタに存在するかどうかを判断し、clusterListコレクション内の各クラスタを走査し、クラスタクラスタ内のsameList属性を取得し、sameListコレクションにポイントが含まれているかどうかを判断します。 , が含まれている場合は true を返します。トラバース後は false を返します。
(6) canReachPoint() メソッドの本体内で、クラスターに含まれるすべての点を走査し、コア オブジェクトの点を除く各点がコア オブジェクトであるかどうかを判断します。クラスター コア ポイントの密度到達可能ポイントもクラスター クラスターにマージでき、これらのポイントは密度到達可能ポイント セットに追加されます。ループが終了すると、セット内のすべての密度到達可能ポイントが追加されます。クラスターの SameList コレクションに移動し、クラスターを再インスタンス化し、最後にクラスターを返します。
(7) getEpointList() メソッドの機能は、点 e のフィールド内のすべての点のコレクションを取得することです。メソッド本体内で、ポイントの e フィールドにすべてのポイントを格納するポイント セット pointList を定義し、データ セット dataList 内の各ポイント p を走査し、Point クラスの静的メソッド CalculateMHDDistance() メソッドを呼び出してポイント ポイントとポイントを計算します。 p マンハッタンの距離は変数 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. 実験の概要

著者は、この実験の結果が正しいことを保証するものではなく、Java 言語を使用して DBSCAN アルゴリズムを実装するためのアイデアを提供しているだけです。実験では答えが得られなかったので、インターネット上にある答え付きの実験データをプログラムに入力し、プログラムが出力した結果は答えと一致しているので、問題は大きくないはずです。うまく書いていないところがあれば、ぜひご指摘ください!
著者のホームページには、他のデータ マイニング アルゴリズムの概要も掲載されています。ぜひご利用ください。

おすすめ

転載: blog.csdn.net/qq_54162207/article/details/128366377