Я создал кодовую книгу с использованием k-средних размера 4000x300 (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
Однако, этот код все еще довольно медленный (для моих целей), и я надеялся, что может быть способ оптимизировать код дальше.
Одна очевидная проблема заключается в том, что существует цикл for, который является препятствием для хорошей производительности на Matlab. Я пытался найти способ избавиться от него, но безуспешно (я изучал использование arrayfun в сочетании с bsxfun, но так и не получил этого). В качестве альтернативы, если кто-то знает какой-либо другой способ ускорить это, я был бы очень признателен.
Обновление
После некоторого поиска я не смог найти отличного решения с использованием 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)
, который использует биномиальную форму евклидова расстояния ((x-y) ^ 2 -> x ^ 2 + y ^ 2 - 2xy), который из того, что я прочитал, обычно работает быстрее. Мой полностью непроверенный перевод Matlab:
XX = sum(data .* data, 2);
YY = sum(center .^ 2, 2);
[val, ~] = max(XX + YY - 2*data*center');