数据结构与算法之聚类算法

  • 一、C 实现聚类算法及代码详解
  • 二、C++ 实现聚类算法及代码详解
  • K-Means 聚类算法
  • 算法原理
  • 代码实现
  • 三、Java 实现聚类算法及代码详解

聚类算法是一种基于数据相似性的无监督学习方法,它的目标是将一组未标记的数据进行分类或者聚成不同的类别。聚类算法可以用于许多应用领域,如生物学、图像处理、推荐系统等。

聚类算法的原理分为两个主要步骤:

  1. 相似性度量

聚类算法的第一步是确定数据之间的相似性度量方法。数据的相似性可以使用各种距离度量方法来度量,如欧几里得距离、曼哈顿距离、余弦距离等。

  1. 聚类

聚类的目标是将数据划分为不同的类别,使得同一类别的数据间相似性尽可能高,而不同类别之间的相似性尽可能低。聚类算法通常分为两大类:基于层次的聚类和基于划分的聚类。

- 基于层次的聚类:又称为层次聚类,它将数据集划分为一个有层次结构的嵌套类别。可以分为自上而下的聚合聚类和自下而上的分裂聚类。这种聚类方法可以可视化类别间的关系,并且不需要预先指定类别数量。

- 基于划分的聚类:又称为划分聚类,它将数据集划分为不同的类别,使得同一类别的数据间相似性尽可能高,而不同类别之间的相似性尽可能低。这种方法需要预先指定类别数量,常见的划分聚类算法包括K均值聚类、支持向量聚类等。

聚类算法可以用于许多应用场景,如推荐系统中的用户聚类、生物学中的基因聚类等。但是需要注意的是,聚类算法并不一定能够得到理想的结果,这取决于数据的质量和特征选择等因素。

java es 分组聚合返回多个字段_支持向量机

一、C 实现聚类算法及代码详解

聚类算法是一种无监督学习方法,通常用于对未标记数据进行分类。在聚类算法中,相似的数据被分组在一起,而不相似的数据则被分到其他组中。C语言是一种常用的编程语言,下面我们将介绍一些常见的聚类算法的C语言实现,包括K-Means、层次聚类和DBSCAN。

  1. K-Means算法的C语言实现

K-Means算法是一种基于距离度量的聚类算法,其主要思想是将数据集分为k个簇,每个簇的中心点是簇中所有点的平均值。以下是K-Means算法的C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define K 2
#define N 10

double distance(double *pt1, double *pt2, int n) {
    double s = 0;
    for (int i = 0; i < n; i++) {
        s += pow(pt1[i] - pt2[i], 2);
    }
    return sqrt(s);
}

void kmeans(double data[N][2], double centers[K][2], int belonging[N]) {
    double dist[N][K];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < K; j++) {
            dist[i][j] = distance(data[i], centers[j], 2);
        }
    }
    for (int i = 0; i < N; i++) {
        int k = 0;
        double d = dist[i][0];
        for (int j = 1; j < K; j++) {
            if (dist[i][j] < d) {
                k = j;
                d = dist[i][j];
            }
        }
        belonging[i] = k;
    }
    for (int j = 0; j < K; j++) {
        double sumx = 0, sumy = 0;
        int count = 0;
        for (int i = 0; i < N; i++) {
            if (belonging[i] == j) {
                sumx += data[i][0];
                sumy += data[i][1];
                count++;
            }
        }
        centers[j][0] = sumx / count;
        centers[j][1] = sumy / count;
    }
}

int main() {
    double data[N][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {2, 0}, {2, 1}, {3, 1}, {3, 0}, {2, -1}, {1, -1}};
    double centers[K][2] = {{0, 0}, {3, 0}};
    int belonging[N] = {0};
    for (int it = 0; it < 10; it++) {
        kmeans(data, centers, belonging);
    }
    for (int i = 0; i < N; i++) {
        printf("(%g, %g) belongs to cluster %d\n", data[i][0], data[i][1], belonging[i]);
    }
    return 0;
}

在这个示例中,我们使用了一个简单的2D数据集来演示K-Means算法的实现。该实现中包含了一个距离函数distance和一个主函数kmeans,其中kmeans函数实现了K-Means算法的核心部分,包括计算距离矩阵、分配簇和更新中心点。

  1. 层次聚类算法的C语言实现

层次聚类算法是一种基于距离度量的聚类方法,其主要思想是通过逐步合并最相似的簇来构建一个层次结构。以下是层次聚类算法的C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define N 10

double distance(double *pt1, double *pt2, int n) {
    double s = 0;
    for (int i = 0; i < n; i++) {
        s += pow(pt1[i] - pt2[i], 2);
    }
    return sqrt(s);
}

void hierarchical_clustering(double data[N][2], int parent[N - 1][2]) {
    double dist[N][N];
    for (int i = 0; i < N; i++) {
        for (int j = i + 1; j < N; j++) {
            dist[i][j] = distance(data[i], data[j], 2);
            dist[j][i] = dist[i][j];
        }
    }
    int n = N, l1, l2;
    while (n > 1) {
        double min_dist = INFINITY;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (dist[i][j] < min_dist) {
                    min_dist = dist[i][j];
                    l1 = i;
                    l2 = j;
                }
            }
        }
        parent[n - 2][0] = l1;
        parent[n - 2][1] = l2;
        for (int i = 0; i < n; i++) {
            if (i != l1 && i != l2) {
                double d1 = dist[i][l1];
                double d2 = dist[i][l2];
                dist[i][n - 1] = (d1 + d2) / 2;
                dist[n - 1][i] = dist[i][n - 1];
            }
        }
        for (int j = 0; j < n; j++) {
            dist[l1][j] = INFINITY;
            dist[j][l1] = INFINITY;
        }
        for (int j = 0; j < n; j++) {
            dist[l2][j] = INFINITY;
            dist[j][l2] = INFINITY;
        }
        n--;
    }
}

void print_tree(int parent[N - 1][2], int current, int level) {
    if (parent[current][0] < 0) {
        printf("%*s%d\n", level * 2, "", parent[current][0]);
    } else {
        printf("%*s(\n", level * 2, "");
        print_tree(parent, parent[current][0], level + 1);
        print_tree(parent, parent[current][1], level + 1);
        printf("%*s)\n", level * 2, "");
    }
}

int main() {
    double data[N][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {2, 0}, {2, 1}, {3, 1}, {3, 0}, {2, -1}, {1, -1}};
    int parent[N - 1][2];
    hierarchical_clustering(data, parent);
    print_tree(parent, N - 2, 0);
    return 0;
}

在这个示例中,我们使用了一个简单的2D数据集来演示层次聚类算法的实现。该实现中包含了一个距离函数distance和一个主函数hierarchical_clustering,其中hierarchical_clustering函数实现了层次聚类算法的核心部分,包括计算距离矩阵、逐步合并簇和构建层次树。该实现还包含一个辅助函数print_tree,用于打印层次树。

  1. DBSCAN算法的C语言实现

DBSCAN算法是一种基于密度的聚类方法,其主要思想是通过寻找高密度区域来将数据点分组。以下是DBSCAN算法的C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define N 10

double distance(double *pt1, double *pt2, int n) {
    double s = 0;
    for (int i = 0; i < n; i++) {
        s += pow(pt1[i] - pt2[i], 2);
    }
    return sqrt(s);
}

void expand_cluster(int p, int c, double data[N][2], int labels[N], double eps, int min_pts) {
    for (int i = 0; i < N; i++) {
        if (labels[i] < 0 && distance(data[p], data[i], 2) < eps

java es 分组聚合返回多个字段_聚类算法_02

二、C++ 实现聚类算法及代码详解

聚类是一种无监督学习方法,它将数据集中相似的数据点划分为一组。C++ 编程语言可以实现聚类算法,其中最常用的算法是 K-Means 和层次聚类。以下是这两种算法的详细解释和代码实现。

K-Means 聚类算法

算法原理

K-Means 算法是一种基于距离度量的聚类方法,其主要思想是将数据集分成 K 个不同的簇,每个簇包含具有相似属性的数据点。算法的核心是使用质心(centroid)作为每个簇的代表。具体流程如下:

  1. 选择 K 个初始质心,可以是随机选择或手动选择;
  2. 将每个数据点分配到距离其最近的质心形成 K 个簇;
  3. 根据簇中所有数据点的均值,重新计算质心;
  4. 重复步骤2和3,直到质心不再改变或达到指定的迭代次数。

代码实现

以下是 K-Means 算法的 C++ 代码实现:

#include <iostream>
#include <cmath>
#include <vector>

using namespace std;

// 计算两个向量之间的距离
double dist(vector<double>& x, vector<double>& y) {
    double sq_sum = 0.0;
    for (int i = 0; i < x.size(); ++i) {
        sq_sum += pow(x[i] - y[i], 2);
    }
    return sqrt(sq_sum);
}

// 根据当前的质心分配数据点
void assign(vector<vector<double>>& data, vector<vector<double>>& centroids, vector<int>& cluster) {
    for (int i = 0; i < data.size(); ++i) {
        double min_dist = numeric_limits<double>::max();
        int idx = -1;
        for (int j = 0; j < centroids.size(); ++j) {
            double d = dist(data[i], centroids[j]);
            if (d < min_dist) {
                min_dist = d;
                idx = j;
            }
        }
        cluster[i] = idx;
    }
}

// 计算每个簇的均值并更新质心
bool update(vector<vector<double>>& data, vector<vector<double>>& centroids, vector<int>& cluster) {
    int k = centroids.size();
    vector<int> cnt(k, 0);
    vector<vector<double>> sum(k, vector<double>(data[0].size(), 0.0));
    for (int i = 0; i < data.size(); ++i) {
        int c = cluster[i];
        cnt[c] += 1;
        for (int j = 0; j < data[i].size(); ++j) {
            sum[c][j] += data[i][j];
        }
    }
    bool changed = false;
    for (int i = 0; i < k; ++i) {
        if (cnt[i] > 0) {
            for (int j = 0; j < sum[i].size(); ++j) {
                double new_centroid = sum[i][j] / cnt[i];
                if (fabs(new_centroid - centroids[i][j]) > 1e-6) {
                    changed = true;

java es 分组聚合返回多个字段_支持向量机_03

三、Java 实现聚类算法及代码详解

聚类算法是一种常用的机器学习算法,它是将数据集中的样本划分为若干个类别,使得同一类别内的样本相似度较高,不同类别之间的样本相似度较低。常用的聚类算法包括 K-means、层次聚类、DBSCAN 等。本文主要介绍 K-means 聚类算法的 Java 实现。

K-means 算法的实现步骤如下:

1.随机选取 K 个初始聚类中心。

2.计算每个样本到 K 个聚类中心的距离,将样本归为距离最近的聚类中心的类别。

3.更新每个聚类的中心,即计算每个聚类中样本的平均值作为新的聚类中心。

4.重新计算每个样本到新的 K 个聚类中心的距离,重复步骤 2 和 3 直到聚类中心不再变化或达到最大迭代次数。

下面是 K-means 聚类算法的 Java 代码实现及详解。

首先,我们定义一个 Point 类表示样本点:

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

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

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    // 计算到另一个点的距离
    public double distance(Point other) {
        double dx = x - other.getX();
        double dy = y - other.getY();
        return Math.sqrt(dx*dx + dy*dy);
    }
}

接下来,我们实现 K-means 算法:

public class Kmeans {
    private List<Point> points; // 样本点集合
    private List<Point> centers; // 聚类中心集合
    private int k; // 聚类数
    private int maxIter; // 最大迭代次数

    public Kmeans(List<Point> points, int k, int maxIter) {
        this.points = points;
        this.k = k;
        this.maxIter = maxIter;
        centers = new ArrayList<>();
    }

    // 选择 K 个随机样本作为聚类中心
    private void initCenters() {
        Random random = new Random();
        for (int i = 0; i < k; i++) {
            Point center = points.get(random.nextInt(points.size()));
            centers.add(center);
        }
    }

    // 将每个样本归为距离最近的聚类中心的类别
    private void assignPoints() {
        for (Point point : points) {
            int label = 0;
            double minDist = Double.MAX_VALUE;
            for (int i = 0; i < k; i++) {
                double dist = point.distance(centers.get(i));
                if (dist < minDist) {
                    minDist = dist;
                    label = i;
                }
            }
            point.setLabel(label);
        }
    }

    // 更新每个聚类的中心
    private void updateCenters() {
        for (int i = 0; i < k; i++) {
            double sumX = 0;
            double sumY = 0;
            int count = 0;
            for (Point point : points) {
                if (point.getLabel() == i) {
                    sumX += point.getX();
                    sumY += point.getY();
                    count++;
                }
            }
            if (count > 0) {
                double centerX = sumX / count;
                double centerY = sumY / count;
                centers.set(i, new Point(centerX, centerY));
            }
        }
    }

    // 执行 K-means 聚类算法
    public void doKmeans() {
        initCenters();
        int iter = 0;
        while (iter < maxIter) {
            assignPoints();
            List<Point> oldCenters = new ArrayList<>(centers);
            updateCenters();
            // 判断聚类中心是否发生变化
            if (oldCenters.equals(centers)) {
                System.out.println("Converged after " + iter + " iterations.");
                return;
            }
            iter++;
        }
        System.out.println("Maximum iteration (" + maxIter + ") exceeded.");
    }
}

在主函数中创建样本点集合,调用 Kmeans 类的 doKmeans 方法执行聚类算法,并输出聚类结果:

public static void main(String[] args) {
    // 创建样本点集合
    List<Point> points = new ArrayList<>();
    points.add(new Point(1,1));
    points.add(new Point(1.5,2));
    points.add(new Point(3,4));
    points.add(new Point(5,7));
    points.add(new Point(3.5,5));
    points.add(new Point(4.5,5));
    points.add(new Point(3.5,4.5));

    // 执行 K-means 聚类算法
    Kmeans kmeans = new Kmeans(points, 2, 10);
    kmeans.doKmeans();

    // 输出聚类结果
    for (Point point : points) {
        System.out.println("Point (" + point.getX() + "," + point.getY() + ") belongs to cluster " + point.getLabel());
    }
}

聚类结果如下:

Converged after 3 iterations.
Point (1.0,1.0) belongs to cluster 0
Point (1.5,2.0) belongs to cluster 0
Point (3.0,4.0) belongs to cluster 1
Point (5.0,7.0) belongs to cluster 1
Point (3.5,5.0) belongs to cluster 1
Point (4.5,5.0) belongs to cluster 1
Point (3.5,4.5) belongs to cluster 1

以上就是 K-means 聚类算法的 Java 实现及代码详解。

java es 分组聚合返回多个字段_算法_04