聚类算法初探
Posted Pentacrest智联万物
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聚类算法初探相关的知识,希望对你有一定的参考价值。
聚类是一种机器学习技术,涉及对数据点进行分组。给定一组数据点,我们可以使用聚类算法将每个数据点分类到特定的组中。理论上,同一组中的数据点应该具有相似的属性和/或特征,而不同组中的数据点应该具有高度不同的属性和/或特征。聚类是一种无监督学习的方法,是用于许多领域的统计数据分析的常用技术。
你可以使用许多不同的方法来执行聚类,事实上,有很多种聚类算法。每一类都有其独特的优势和劣势。这意味着某些聚类算法将根据输入数据产生更自然的聚类分配。为数据集选择合适的聚类算法通常很困难,因为可用的选择太多了。影响这个决策的一些重要因素包括集群的特性、数据集的特性、异常值的数量和数据对象的数量。
三类流行的聚类算法包括:Partitional clustering, Hierarchical clustering, Density-basedclustering。
以下介绍各类方法的优缺点
1.Partitional clustering
Partitional clustering将数据对象划分为不重叠的组。换句话说,没有对象可以是多个集群的成员,每个集群必须至少有一个对象。这些技术要求用户指定由变量k表示的聚类数目。许多Partitional clustering算法通过迭代过程将数据点子集分配到k个聚类中。Partitional clustering算法的两个例子是k-means和k-medoids。这些算法都是不确定性的,这意味着即使运行基于相同的输入,它们也可以从两个不同的运行中产生不同的结果。
Partitional clustering法有几个优点:当每一类分布呈球形时,它们工作得很好。它们在算法复杂度方面是scalable的。
它们也有几个缺点:它们不太适合形状复杂、大小不一的簇。当与不同密度的集群一起使用时,它们会失效。
此类方法中最著名的当属Kmeans clustering方法,下边有详细描述。
2.Hierarchical clustering
Hierarchical clustering通过构建层次结构来确定聚类分配。这可以通过自下而上或自上而下的方法来实现:Hierarchical聚类是自下而上的方法,它将合并最相似的两个点,直到所有点都合并到某一个簇中;Partitional clustering是自顶向下的方法,它从所有点作为一个簇开始,在每一步中分割最不相似的簇,直到只剩下一个数据点。这些方法生成一个基于树的点层次结构,称为树状图。与Partitional clustering类似,在Hierarchical clustering中,cluster的数目(K)通常由用户预先确定。通过在指定的深度切割树状图来分配聚类,从而产生K组较小的树状图。与许多Partitional clustering技术不同,Hierarchical clustering是一个确定的过程,这意味着在相同的输入数据上运行两次算法时,集群分配不会改变。
Hierarchical clustering法的优点包括:它们常常揭示数据对象之间关系的更精细的细节。它们提供了一个可解释的树状图。
Hierarchical clustering方法的缺点包括:就算法复杂度而言,它们的计算成本很高。它们对data noise和outliers很敏感。
3.Density-based clustering
Density-based clustering根据区域中数据点的密度来确定聚类分配。在由低密度区域分隔的高密度数据点处分配簇。与其他聚类方法不同,这种方法不需要用户指定集群的数量。相反,有一个基于距离的参数充当可调阈值。此阈值决定了必须将多近的点视为群集成员。Density-based clustering算法的示例包括基于密度的应用程序(DBSCAN)的空间聚类(DBSCAN)和用于识别聚类结构的排序点(OPTICS)。
Density-based 方法的优势包括:它们擅长于识别非球形形状的簇。它们对异常值有抵抗力。
Density-based 方法的缺点包括:它们不太适合在高维空间中进行聚类。它们很难识别不同密度的cluster。
下文详细介绍两种常见的聚类算法:
K-means clustering
K-Means 可能是最著名的partitional聚类算法。它在许多介绍性的数据科学和机器学习课程中都有教授。在代码中很容易理解和实现!下面给出了算法细节。
Given data set {x_i}, i=1,..N in D-dimensional Euclidean space partition into K clusters (which is given) Indicator variable rnk ∈ {0,1} where k =1,..,K – Describes which of K clusters data point x_n is assigned to. Objective function is the sum of squares of distances of each data point to its assigned vector µ_k. To minimize the distance of each data point‘s distance to the centroids, just follow the algorithm below:
下面是Kmeans使用c++编写的一个分类实例:
using namespace std;
// Create point struction in 1D
struct Point {
double x; // 坐标
int cluster; // no default cluster
double minDist;
Point() : x(0.0), cluster(-1), minDist(__DBL_MAX__) {}
Point(double x) : x(x), cluster(-1), minDist(__DBL_MAX__) {}
/**
* 计算欧式距离
*/
double distance(Point p) {
return (p.x - x) * (p.x - x);
}
};
/**
* 建立0-100的随机整数数列;
*/
vector<Point> createPoints(int pnumber) {
vector<Point> points;
for (int i=1;i<=pnumber;i++){
points.push_back(Point( rand()%100 ));
}
return points;
}
/**
* Perform k-means clustering
* @param points - pointer to vector of points
* @param epochs - kmeans 循环次数
* @param k - 群组个数
*/
void kMeans(vector<Point>* points, int epochs, int k) {
int n = points->size();
// 随机选定群组中心
// 群组的index就是群组label
vector<Point> centroids;
srand(time(0));
for (int i = 0; i < k; ++i) {
centroids.push_back(points->at(rand() % n));
}
//进入循环:对分组进行epochs次的重新分组
for (int i = 0; i < epochs; ++i) {
// For each centroid, compute distance from centroid to each point
// and update point's cluster if necessary
for (vector<Point>::iterator c = begin(centroids); c != end(centroids);
++c) {
int clusterId = c - begin(centroids);
for (vector<Point>::iterator it = points->begin();
it != points->end(); ++it) {
Point p = *it;
double dist = c->distance(p);
if (dist < p.minDist) {
p.minDist = dist;
p.cluster = clusterId;
}
*it = p;
}
}
vector<int> nPoints;
vector<double> sumX;
for (int j = 0; j < k; ++j) {
nPoints.push_back(0);
sumX.push_back(0.0);
}
for (vector<Point>::iterator it = points->begin(); it != points->end();
++it) {
int clusterId = it->cluster;
nPoints[clusterId] += 1;
sumX[clusterId] += it->x;
it->minDist = __DBL_MAX__; // reset distance
}
for (vector<Point>::iterator c = begin(centroids); c != end(centroids);
++c) {
int clusterId = c - begin(centroids);
c->x = sumX[clusterId] / nPoints[clusterId];
}
}
for(int j = 0;j<k; j++){
cout<<"Cluster "<<j<<" members"<<endl;
for (vector<Point>::iterator it = points->begin(); it != points->end();
++it) {
if (it->cluster==j) cout << it->x << endl;
}
}
}
int main() {
vector<Point> points =createPoints(30);
// 将待分类数组分入3类目标群组,运行200次循环
kMeans(&points, 200, 3);
}
K-Means 有几个缺点。首先,你必须选择有多少组/群。这可能是至关重要的,理想情况下,我们希望使用聚类算法为我们解决这些问题,因为它的重点是从数据中获得一些深入了解,但是预设分类组数首先假定我们对数据有一定了解,实时不总是这样。 另外K-means 从随机选择聚类中心开始,因此它可能会在算法的不同运行中产生不同的聚类结果。因此,结果可能不可重复且缺乏一致性。其他聚类方法分类结果更加一致。
K-Medians 是另一种与 K-Means 相关的聚类算法,除了我们使用组的中值向量而不是使用均值重新计算组中心点。这种方法对异常值不太敏感(因为使用中值),但对于较大的数据集要慢得多,因为在计算中值向量时每次迭代都需要排序。
以上是关于聚类算法初探的主要内容,如果未能解决你的问题,请参考以下文章