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

来源:互联网 发布:淘宝买家注册时间 编辑:程序博客网 时间:2024/05/12 08:04

背景

在对大样本进行聚类时,由于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=2Cp+p_norm
6. 计算dis中最小的那个数据的index,即为离点p最近的聚类中心

分析

为什么第5步中的算式就得到距离了呢?
答:设C中的一个聚类中心向量为(c1,c2,...,c2000), 样本点p为(p1,p2,...,p2000), 则第1步中的归一化即为p21+...+p22000, 第2步中的归一化即为c21+...+c22000, 则5中的算式其实为:

2(p1c1+...+p2000c2000)+p21+...+p22000+c21+...+c22000

即:
(p1c1)2+...+(pncn)2

C++代码

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

// 设有一个数据点vector<float> point//    聚类中心vector<float> vocabs, float* vocabs_matrices// centroids_norms_为第2步中的聚类中心normfloat 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开始的
2 0
原创粉丝点击