数据结构与算法之聚类算法
- 一、C 实现聚类算法及代码详解
- 二、C++ 实现聚类算法及代码详解
- K-Means 聚类算法
- 算法原理
- 代码实现
- 三、Java 实现聚类算法及代码详解
聚类算法是一种基于数据相似性的无监督学习方法,它的目标是将一组未标记的数据进行分类或者聚成不同的类别。聚类算法可以用于许多应用领域,如生物学、图像处理、推荐系统等。
聚类算法的原理分为两个主要步骤:
- 相似性度量
聚类算法的第一步是确定数据之间的相似性度量方法。数据的相似性可以使用各种距离度量方法来度量,如欧几里得距离、曼哈顿距离、余弦距离等。
- 聚类
聚类的目标是将数据划分为不同的类别,使得同一类别的数据间相似性尽可能高,而不同类别之间的相似性尽可能低。聚类算法通常分为两大类:基于层次的聚类和基于划分的聚类。
- 基于层次的聚类:又称为层次聚类,它将数据集划分为一个有层次结构的嵌套类别。可以分为自上而下的聚合聚类和自下而上的分裂聚类。这种聚类方法可以可视化类别间的关系,并且不需要预先指定类别数量。
- 基于划分的聚类:又称为划分聚类,它将数据集划分为不同的类别,使得同一类别的数据间相似性尽可能高,而不同类别之间的相似性尽可能低。这种方法需要预先指定类别数量,常见的划分聚类算法包括K均值聚类、支持向量聚类等。
聚类算法可以用于许多应用场景,如推荐系统中的用户聚类、生物学中的基因聚类等。但是需要注意的是,聚类算法并不一定能够得到理想的结果,这取决于数据的质量和特征选择等因素。
一、C 实现聚类算法及代码详解
聚类算法是一种无监督学习方法,通常用于对未标记数据进行分类。在聚类算法中,相似的数据被分组在一起,而不相似的数据则被分到其他组中。C语言是一种常用的编程语言,下面我们将介绍一些常见的聚类算法的C语言实现,包括K-Means、层次聚类和DBSCAN。
- 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算法的核心部分,包括计算距离矩阵、分配簇和更新中心点。
- 层次聚类算法的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
,用于打印层次树。
- 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
二、C++ 实现聚类算法及代码详解
聚类是一种无监督学习方法,它将数据集中相似的数据点划分为一组。C++ 编程语言可以实现聚类算法,其中最常用的算法是 K-Means 和层次聚类。以下是这两种算法的详细解释和代码实现。
K-Means 聚类算法
算法原理
K-Means 算法是一种基于距离度量的聚类方法,其主要思想是将数据集分成 K 个不同的簇,每个簇包含具有相似属性的数据点。算法的核心是使用质心(centroid)作为每个簇的代表。具体流程如下:
- 选择 K 个初始质心,可以是随机选择或手动选择;
- 将每个数据点分配到距离其最近的质心形成 K 个簇;
- 根据簇中所有数据点的均值,重新计算质心;
- 重复步骤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 实现聚类算法及代码详解
聚类算法是一种常用的机器学习算法,它是将数据集中的样本划分为若干个类别,使得同一类别内的样本相似度较高,不同类别之间的样本相似度较低。常用的聚类算法包括 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 实现及代码详解。