Упрощение сложного выражения


У меня есть это сложное выражение 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 3

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 или любую другую не встроенную функцию; или, как Дивакар любезно показал в своем ответе, просто полностью избавиться от всех циклов.