Упрощение сложного выражения
У меня есть это сложное выражение MATLAB, которое я хотел бы упростить, чтобы действительно понять его.
g = repmat(log(p), [size(x, 1), 1])
for i = 1:size(mu, 1)
g(:, i) = g(:, i) - sum(log(sigma(i, :)));
g(:, i) = g(:, i) - sum(bsxfun(@rdivide, bsxfun(@minus, x, mu(i, :)).^2, 2*sigma(i, :).^2), 2);
end
p=1x2
sigma=2x2
mu=2x2
x=30x2
В основном эти функции bsxfun меня очень смущают. Я хотел бы выразить это в виде простых for петель.
Я попробовал что-то вроде этого:
[m,n] = size(x)
for i=1:m
for j=1:n
g(i,j)= log(p(j)) - sum(log(sigma(j))) - sum(data(i,j))... ;
end
end
Не совсем уверен, как продолжить с этого момента, в основном ошибки и неправильные результаты!
2 ответа:
По-видимому, код в вопросе может быть использован в качестве хорошей
bsxfunиpermuteпрактической сессии для векторизации всего. Я понимаю, что это идет в другую сторону от того, что задано в вопросе, но примите это как альтернативное решение.Возвращаясь назад, чтобы фактически векторизовать все, вам нужно расширить размеры с помощью
permuteи продолжайте использоватьbsxfun. Реализация будет выглядеть следующим образом -%// Vectorize : "g(:, i) = g(:, i) - sum(log(sigma(i, :)))" parte1 = bsxfun(@minus,g,sum(log(sigma),2).'); %//' %// Vectorize : "bsxfun(@minus, x, mu(i, :)).^2" parte2_1 = bsxfun(@minus,x,permute(mu,[3 2 1])).^2; %// Vectorize : "bsxfun(@rdivide, ...*sigma(i, :).^2)" parte2 = bsxfun(@rdivide,parte2_1,2*permute(sigma,[3 2 1]).^2); %// Squeeze in dimensions of the BSXFUN extended array and subtract from parte1 g = parte1 - squeeze(sum(parte2,2));
Я просто объясню тебе.
bsxfun, поскольку замена этого для петлиforпохожа на замену вашего автомобиля на велосипед с точки зрения скорости.Общее введение в
bsxfunможно найтиздесь в этом фантастическом ответеДивакара .Давайте сократим вашу программу по частям:
Это просто говорит вам, что каждый элемент вbsxfun(@minus, x, mu(i, :))xвычитается (@minus) из каждого элемента вmu(i,:). Теперь этоbsxfunвложено в другой:bsxfun(@rdivide, bsxfun(@minus, x, mu(i, :)).^2, 2*sigma(i, :).^2)Это
bsxfunразделяет две вещи, следовательно,rdivide. Каждый элемент, полученный вычитанием из ранее рассмотренногоbsxfun, делится на каждый элемент в2*sigma(i,:).^2, который является массивом.Наконец,
sumвсей вещи берется для получения одного значения. Это вычитается из исходной записи дляg(:,i)для каждого экземпляраi.Обратите внимание, что это очень плохая практика использовать
iилиjв качестве переменной , так что один из улучшений этого кода следует изменитьiна, например,iiилиnили любую другую не встроенную функцию; или, как Дивакар любезно показал в своем ответе, просто полностью избавиться от всех циклов.