首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >K-均值聚类R-Tree boost

K-均值聚类R-Tree boost
EN

Stack Overflow用户
提问于 2018-03-04 17:36:32
回答 1查看 952关注 0票数 0

我使用的是R-Tree boost。我在r-tree boost中添加了10万个点。现在,我想像这个link一样对我的点进行聚类和分组。似乎我应该从点数来计算k-均值。如何从r-tree点几何中计算k-均值?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-17 08:57:12

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

有各种用于不同数据和应用的k-means聚类算法,如使用超平面分离2n维子集或使用Voronoi图(Lloyd算法)聚类,通常称为k-means算法。还有@Anony-Mousse在你问题下的评论中提到的基于密度的聚类算法。

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

使用Boost.Geometry R-树,一个级别的算法(所以不是分层的)可以像这样(在C++11中)实现:

代码语言:javascript
复制
#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;
        }
    }
}

另请参阅它们的实现:https://github.com/mapbox/supercluster/blob/master/index.js#L216

此外,考虑到@Anony-Mousse关于全球距离计算准确性的评论。上面的解决方案适用于笛卡尔坐标系。如果要使用不同的坐标系,则必须以不同的方式定义点类型,例如,使用bg::cs::spherical_equatorial<bg::degree>bg::cs::geographic<bg::degree>而不是bg::cs::cartesian。您还必须以不同的方式生成查询边界框。但是,在更改点类型后,bg::distance()将自动返回正确的距离。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49093958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档