C++ K-均值聚类R-树boost

C++ K-均值聚类R-树boost,c++,boost,k-means,boost-geometry,r-tree,C++,Boost,K Means,Boost Geometry,R Tree,我正在使用。我在r树中增加了十万点。现在我想像这样对我的点进行聚类和分组。看起来我应该从点开始计算k均值。如何从r-树点几何计算k-均值。有各种聚类算法,它们具有不同的属性和输入。在选择算法之前需要考虑的是您想要实现的目标。您在问题中提到的k-means旨在将点集划分为k个簇。因此,输入是所需的簇数。另一方面,您链接的博客中描述的算法是贪婪聚类算法的一种变体,它旨在将一组点划分为一定大小的圆形聚类。输入是所需簇的半径 对于不同的数据和应用,有多种算法执行k-means聚类,如使用超平面分离2个n

我正在使用。我在r树中增加了十万点。现在我想像这样对我的点进行聚类和分组。看起来我应该从点开始计算k均值。如何从r-树点几何计算k-均值。

有各种聚类算法,它们具有不同的属性和输入。在选择算法之前需要考虑的是您想要实现的目标。您在问题中提到的k-means旨在将点集划分为k个簇。因此,输入是所需的簇数。另一方面,您链接的博客中描述的算法是贪婪聚类算法的一种变体,它旨在将一组点划分为一定大小的圆形聚类。输入是所需簇的半径

对于不同的数据和应用,有多种算法执行k-means聚类,如使用超平面分离2个n维子集或使用Voronoi图(劳埃德算法)进行聚类,通常称为k-means算法。还有@Anony Mouse在您的问题下的评论中提到的基于密度的聚类算法

在文章中,您提到了它是贪婪聚类的一个分层版本。他们必须计算多个缩放级别的簇,并避免每次使用先前分析级别的簇质心作为下一级别簇的点源时分析所有点。然而,在这个答案中,我将展示如何只在一个级别上实现这个算法。因此,输入将是一组点和一个半径大小的簇。如果需要分层版本,则应计算输出集群的质心,并将其用作下一级别算法的输入

使用Boost.Geometry R-tree,一个级别(因此不是层次结构)的算法可以实现如下(在C++11中):

#包括
#包括
#包括
#包括
#包括
#包括
名称空间bg=boost::geometry;
名称空间bgi=boost::geometry::index;
typedef bg::model::point\t;
typedef bg::model::box\t;
typedef std::向量簇;
//在rtree构造函数中与Boost.Range适配器一起使用
//动态从点生成std::pair
模板
结构对生成器
{
typedef std::pair result_type;
模板
内联结果类型运算符()(T常量和v)常量
{
返回结果类型(v.value(),v.index());
}
};
//用于在聚类过程中保留点相关信息
结构点数据
{
point_data():已使用(false){}
布尔使用;
};
//使用簇半径r查找点簇
void find_集群(标准::向量常量和点,
双r,
std::向量和簇)
{
typedef std::对值\u t;
类型定义对\u生成器值\u生成器;
if(r<0.0)
return;//或返回错误
//创建包含std::pair的rtree
//从类型为point\u t的点的容器
bgi::rtree
rtree(points | boost::adapters::index())
|boost::adaptors::transformed(value_generator());
//创建容器保持点状态
std::vector points_data(rtree.size());
//对于rtree中包含的所有对
用于(自动const&v:rtree)
{
//忽略以前使用过的点
if(点\数据[v.second]。已使用)
继续;
//当前点
点常数&p=v.first;
双x=bg::get(p);
双y=bg::get(p);
//找到当前点周围半径为r的圆中的所有点
std::向量res;
rtree.query(
//包含圆的框中的返回点
bgi::相交(长方体{x-r,y-r},{x+r,y+r})
//以前没有用过
//他们确实在这个圈子里
&&bgi::满足([&](值常数&v){
返回点\u数据[v.second]。已使用==false

&&bg::距离(p,v.优先)有各种不同的聚类算法,它们具有不同的属性和输入。在选择算法之前需要考虑的是您想要实现什么。您在问题中提到的k-means旨在将点集划分为k个簇。因此,输入是所需的簇数。另一方面,算法描述在你链接的博客中,贪婪聚类算法的一个变种旨在将一组点划分成一定大小的圆形聚类。输入是所需聚类的半径

对于不同的数据和应用,有不同的算法执行k-means聚类,如用超平面分离2个n维子集或用Voronoi图聚类(劳埃德算法)通常称为k-means算法。还有@Anony Mouse在您问题的评论中提到的基于密度的聚类算法

在文章中,您提到了贪婪聚类的分层版本。他们必须计算多个缩放级别的聚类,避免每次使用之前分析级别的聚类质心作为下一级别聚类的点源时分析所有点。但是,在这个回答中,我我将演示如何在一个级别上实现此算法。因此,输入将是一组点和一个半径大小的簇。如果需要分层版本,则应计算输出簇的质心,并将其用作下一级别算法的输入

使用Boost.Geometry R-tree,一个级别(因此不是层次结构)的算法可以实现如下(在C++11中):

#包括
#包括
#包括
#包括
#包括
#包括
名称空间bg=boost::geometry;
名称空间bgi=boost::geometry::index;
typedef bg::model::point\t;
typedef bg::model::box\t;
typedef std::向量簇;
//在带有Boost.Range适配器的rtree构造函数中使用
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>

#include <boost/range/adaptor/indexed.hpp>
#include <boost/range/adaptor/transformed.hpp>

#include <iostream>
#include <vector>

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

typedef bg::model::point<double, 2, bg::cs::cartesian> point_t;
typedef bg::model::box<point_t> box_t;
typedef std::vector<point_t> cluster_t;

// used in the rtree constructor with Boost.Range adaptors
// to generate std::pair<point_t, std::size_t> from point_t on the fly
template <typename First, typename Second>
struct pair_generator
{
    typedef std::pair<First, Second> result_type;
    template<typename T>
    inline result_type operator()(T const& v) const
    {
        return result_type(v.value(), v.index());
    }
};

// used to hold point-related information during clustering
struct point_data
{
    point_data() : used(false) {}
    bool used;
};

// find clusters of points using cluster radius r
void find_clusters(std::vector<point_t> const& points,
                   double r,
                   std::vector<cluster_t> & clusters)
{
    typedef std::pair<point_t, std::size_t> value_t;
    typedef pair_generator<point_t, std::size_t> value_generator;

    if (r < 0.0)
        return; // or return error

    // create rtree holding std::pair<point_t, std::size_t>
    // from container of points of type point_t
    bgi::rtree<value_t, bgi::rstar<4> >
        rtree(points | boost::adaptors::indexed()
                     | boost::adaptors::transformed(value_generator()));

    // create container holding point states
    std::vector<point_data> points_data(rtree.size());

    // for all pairs contained in the rtree
    for(auto const& v : rtree)
    {
        // ignore points that were used before
        if (points_data[v.second].used)
            continue;

        // current point
        point_t const& p = v.first;
        double x = bg::get<0>(p);
        double y = bg::get<1>(p);

        // find all points in circle of radius r around current point
        std::vector<value_t> res;
        rtree.query(
            // return points that are in a box enclosing the circle
            bgi::intersects(box_t{{x-r, y-r},{x+r, y+r}})
            // and were not used before
            // and are indeed in the circle
            && bgi::satisfies([&](value_t const& v){
                   return points_data[v.second].used == false
                       && bg::distance(p, v.first) <= r;
            }),
            std::back_inserter(res));

        // create new cluster
        clusters.push_back(cluster_t());
        // add points to this cluster and mark them as used
        for(auto const& v : res) {
            clusters.back().push_back(v.first);
            points_data[v.second].used = true;
        }
    }
}

int main()
{
    std::vector<point_t> points;

    for (double x = 0.0 ; x < 10.0 ; x += 1.0)
        for (double y = 0.0 ; y < 10.0 ; y += 1.0)
            points.push_back(point_t{x, y});

    std::vector<cluster_t> clusters;

    find_clusters(points, 3.0, clusters);

    for(size_t i = 0 ; i < clusters.size() ; ++i) {
        std::cout << "Cluster " << i << std::endl;
        for (auto const& p : clusters[i]) {
            std::cout << bg::wkt(p) << std::endl;
        }
    }
}