Shark源码分析(六):k-means算法
k-means算法是原型聚类算法中一个非常典型的算法。关于聚类算法,我之后应该会在博客中进行详细说明。
对于整个聚类算法来说,可以分为两类:硬聚类与软聚类。对于硬聚类,每一个数据点只能属于某一个簇。对于软聚类来说,则没有这一限制。
首先还是来看一下整个聚类算法基类。
ClusteringModel类
ClusteringModel类定义在<include/shark/Models/Clustering/ClusteringModel.h>
文件中。
template <class InputT, class OutputT>
class ClusteringModel : public AbstractModel<InputT, OutputT>
{
public:
typedef AbstractModel<InputT, OutputT> base_type;
typedef AbstractClustering<InputT> ClusteringType;
typedef typename base_type::BatchInputType BatchInputType;
typedef typename base_type::BatchOutputType BatchOutputType;
ClusteringModel(ClusteringType* clustering)
: mep_clustering(clustering)
{ SHARK_CHECK(clustering, "[ClusteringModel] Clustering must not be NULL"); }
//稍后你可能会发现AbstractClustering类其实并没有parameterVector这一函数,其子类中是含有的,那么编译起来不会报错吗
//注意到这里mep_clustering的定义类型是ClusteringType*,那么它肯定会使用到多态
//只要其传入的对象中定义有parameterVector这一函数即可
RealVector parameterVector() const
{ return mep_clustering->parameterVector(); }
void setParameterVector(RealVector const& newParameters)
{ mep_clustering->setParameterVector(newParameters); }
std::size_t numberOfParameters() const
{ return mep_clustering->numberOfParameters(); }
void read(InArchive& archive)
{ archive & *mep_clustering; }
void write(OutArchive& archive) const
{ archive & *mep_clustering; }
using base_type::eval;
//计算数据所属簇的标签
void eval(BatchInputType const& patterns, BatchOutputType& outputs, State& state)const{
eval(patterns,outputs);
}
protected:
ClusteringType* mep_clustering; // 使用的是基类指针,方便使用多态
};
AbstractClustering类
在ClusteringModel类中你可能发现了AbstractClustering这个类,那么这个类又是干什么的呢?如果你熟悉基于原型的聚类算法的话,你应该知道,其中最重要的一点就是计算各个簇的中心,Shark中将聚类中心也包装成为一个类,而AbstractClustering类就是聚类中心类的基类。
ClusteringModel类包含了AbstractModel类和AbstractClustering类。其中只是提供了一些访问的接口,主要的数据是存储在AbstractClustering类中。
该类的定义位于<include/shark/Models/Clustering/AbstractClustering.h>
文件中。
template <class InputT>
class AbstractClustering : public INameable, public IParameterizable, public ISerializable
{
public:
typedef InputT InputType;
typedef unsigned int OutputType;
typedef typename Batch<InputType>::type BatchInputType;
typedef Batch<OutputType>::type BatchOutputType;
enum Feature {
HAS_SOFT_MEMBERSHIP = 1,
};
SHARK_FEATURE_INTERFACE;
//表示该聚类方法是否能进行软聚类
bool hasSoftMembershipFunction()const{
return m_features & HAS_SOFT_MEMBERSHIP;
}
//返回聚类结果中簇的数目
virtual std::size_t numberOfClusters() const = 0;
//计算一个数据所对应的簇的标号,有batch与非batch的重载版本
//这个函数是针对硬聚类来说的,对于软聚类也有同样的版本
virtual unsigned int hardMembership(InputType const& pattern) const{
typename Batch<InputType>::type b = Batch<InputType>::createBatch(pattern);
get(b,0) = pattern;
return hardMembership(b)(0); //将非batch形式转换为batch形式进行处理
}
// 默认语意是返回softMembership函数返回值的最大值
// 可以看出,硬聚类也是建立在软聚类之上的,只是输出最可能的簇
virtual BatchOutputType hardMembership(BatchInputType const& patterns) const{
std::size_t numPatterns = boost::size(patterns);
RealMatrix f = softMembership(patterns); // 函数返回的应该是对每个簇的隶属度
SHARK_ASSERT(f.size2() > 0);
SHARK_ASSERT(f.size1() == numPatterns);
BatchOutputType outputs(numPa