您的位置:首页 > 编程语言 > MATLAB

function 将数据点分配到最近的聚类中心

2017-01-11 22:20 225 查看

背景

在对大样本进行聚类时,由于k-means的计算开销问题,通常随机选取部分样本进行聚类,得到聚类中心。然而往往要得到每个样本最近聚类中心,这常用在检索索引构建中,eg. OPQ (PAMI 2014)Inverted Multi-Index(PAMI 2014)

算法步骤

设一个特征向量p(1*2000),2000是特征维数。聚类中心矩阵为C(256*2000),256为中心数,2000为特征维数。

1. 数据归一化

对p各维计算平方和,得到p_norm,是一个浮点数。

2. 聚类中心归一化

对C的每一行,计算各维平方和,得到c_norm:256*1

3. p_norm 扩展至 1*256

4. 计算p_norm = p_norm+c_norm;

5. 计算点p到256个中心的距离向量dis=−2C∗p+p_norm

6. 计算dis中最小的那个数据的index,即为离点p最近的聚类中心

分析

为什么第5步中的算式就得到距离了呢?

答:设C中的一个聚类中心向量为(c1,c2,...,c2000), 样本点p为(p1,p2,...,p2000), 则第1步中的归一化即为p21+...+p22000, 第2步中的归一化即为c21+...+c22000, 则5中的算式其实为:−2(p1∗c1+...+p2000∗c2000)+p21+...+p22000+c21+...+c22000

即:

(p1−c1)2+...+(pn−cn)2:)

C++代码

要用到blas库, blas函数的功能解释请查询官网document

// 设有一个数据点vector<float> point
//    聚类中心vector<float> vocabs, float* vocabs_matrices
// centroids_norms_为第2步中的聚类中心norm
float p_norm = cblas_sdot(feature_dim, &(point[0]), 1, &(point[0]), 1);
cblas_saxpy(vocabs_[0].size(), 1,
(centroids_norms_[0]), 1, &(p_norms_[0]), 1);
cblas_sgemv(CblasRowMajor, CblasNoTrans,
vocabs_[0].size(), subspace_dimension, -2.0,
vocabs_matrices_[0], feature_dim, &(point[0]), 1, 1, &(p_norms_[0]), 1);


Matlab代码

Matlab for循环的效率低,用矩阵运算。

设数据矩阵P为10000*2000,其中2000是特征维数,10000是样本数聚类中心矩阵为C为256*2000,256为中心数,2000为特征维数。

1. 数据归一化

对P的每一行,计算各维平方和(实际实现中的归一化一般不做开平方),得到P_norm:10000*1。

2. 聚类中心归一化

对C的每一行,计算各维平方和,得到C_norm:256*1

3. P_norm 扩展至 10000*256(将原来的10000*1的P_norm复制9999遍,按列填充矩阵), C_norm扩展至256*10000(同上,也是复制填充向量得出)。

4. 其后步骤同上。

% 将数据点分配到附近的聚类中心
% Input:
%    points vocab 都按列组织,eg. points中一列位一个特征,行数为特征维数,列数为样本数
% Output:
%    idx_table 为每个样本分配到的最近的聚类中心的下标(从0开始!)
function idx_table = calidx(points, vocab)
disp('Cal coarse ids...');
n_vocab = size(vocab, 2);
N = size(points, 2);
idx_table = zeros(N, 1);

vocab_norm = sum(vocab .^ 2, 1);   % get a row vector

p_norm = repmat(sum(points .^ 2, 1), [n_vocab, 1]) + repmat(vocab_norm', [1, N]); % get n_vocab*N

dis = -2.0 * vocab' * points + p_norm;  % get n_vocab * N dis

[~, idx_table] = min(dis, [], 1);

idx_table = idx_table - 1;  % Matlab下标从1开始,转成从0开始的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 matlab c++ 聚类