サイズ4000x300のk-means(4000セントロイド、それぞれ300の機能)を使用してコードブックを作成しました。次に、コードブックを使用して、入力ベクトルにラベルを付けます(後でビニングするため)。入力ベクトルのサイズはNx300です。ここで、Nは私が受け取る入力インスタンスの総数です。
ラベルを計算するために、各入力ベクトルに最も近い重心を計算します。そのために、各入力ベクトルをすべての重心と比較し、最小距離の重心を選択します。その場合、ラベルはその重心の単なるインデックスになります。
私の現在のMatlabコードは次のようになります。
function labels = assign_labels(centroids, X)
labels = zeros(size(X, 1), 1);
% for each X, calculate the distance from each centroid
for i = 1:size(X, 1)
% distance of X_i from all j centroids is: sum((X_i - centroid_j)^2)
% note: we leave off the sqrt as an optimization
distances = sum(bsxfun(@minus, centroids, X(i, :)) .^ 2, 2);
[value, label] = min(distances);
labels(i) = label;
end
ただし、このコードは(私の目的では)まだかなり遅いので、コードをさらに最適化する方法があるのではないかと期待していました。
明らかな問題の1つは、Matlabでの良好なパフォーマンスの悩みの種であるforループがあることです。私はそれを取り除く方法を考え出そうとしていましたが、運がありませんでした(bsxfunと組み合わせてarrayfunを使用することを検討しましたが、それが機能するようにはなりませんでした)。あるいは、誰かがこれをスピードアップする他の方法を知っているなら、私はそれを大いに感謝します。
アップデート
検索を行った後、Matlabを使用した優れたソリューションが見つからなかったため、Pythonのscikits.learnパッケージで「euclidean_distance」(短縮)に使用されているものを確認することにしました。
XX = sum(X * X, axis=1)[:, newaxis]
YY = Y.copy()
YY **= 2
YY = sum(YY, axis=1)[newaxis, :]
distances = XX + YY
distances -= 2 * dot(X, Y.T)
distances = maximum(distances, 0)
これは、ユークリッド距離の二項形式((xy)^ 2-> x ^ 2 + y ^ 2- 2xy)を使用します。これは、私が読んだものから、通常はより高速に実行されます。私の完全にテストされていないMatlabの翻訳は次のとおりです。
XX = sum(data .* data, 2);
YY = sum(center .^ 2, 2);
[val, ~] = max(XX + YY - 2*data*center');