Использование accmarray для вывода матрицы

От Matlab accumarray невероятно мощный во многих приложениях. Моя проблема в том, что мой accumarray Функция для применения на моих входах имеет три выхода, и accumarray может обрабатывать только скалярные выходы. Например, я хотел бы сделать что-то вроде этого:

subs = [1;2;4;2;4;5];
vals = [1;1;1;2;5;1];
accumarray(subs, vals, [], @(x)[min(x),mean(x),max(x)],0)

и имеют accumarray вернуть:

1.0000    1.0000         0    1.0000    1.0000
1.0000    1.5000         0    3.0000    1.0000
1.0000    2.0000         0    5.0000    1.0000

Я полагаю, я мог бы просто бежать accumarray три раза, но моя функция работает медленно и работает accumarray один раз будет намного быстрее, чем запустить его три раза. Я только что накрылся здесь?

1 ответ

Вы можете обмануть, чтобы анонимная функция выводила массив ячеек вместо одного значения. Сюда, accumarray даст вам массив ячеек матриц. После этого вы можете объединить все матрицы в одну матрицу. Обратите внимание, что предложенная анонимная функция имеет min, max а также mean как вектор строки, но ожидаемый результат - вектор столбца. Поэтому я перенес это в вашу анонимную функцию.

Гоча, которую мы должны принять во внимание, является значением заполнения. Указанное вами значение заполнения должно быть скалярным. Таким образом, вы можете обмануть, пропустив это, но тогда ваш вывод теперь будет содержать пустые матрицы в ячейке вместо строки результата, заполненной 0. Способ обойти это - найти все пустые ячейки, заменить их на ряд нулей, затем соберите все вместе, когда закончите. Чтобы выяснить, какие строки accumarray выход будет пустым, вы можете использовать cellfun в сочетании с isempty так что мы можем видеть, какие элементы в результате пусты. Более точный способ сделать это состоит в том, чтобы сначала предварительно выделить матрицу zeros затем заполнять только те строки, которые соответствуют непустым местам в выходных данных accumarray чтобы закончить это:

subs = [1;2;4;2;4;5];
vals = [1;1;1;2;5;1];
out = accumarray(subs, vals, [], @(x){[min(x),mean(x),max(x)].'});
ind_empty = cellfun('isempty', out);
out_final = zeros(3, numel(out));
out_final(:, ~ind_empty) = cat(2, out{:});

Принять к сведению использование cat который объединяет матрицы вместе в указанном измерении. дела out{:} создает так называемый список через запятую, поэтому он эквивалентен взятию каждого столбца accumarray вывод и положить их в качестве отдельных аргументов в cat так что в конечном итоге мы собираем все столбцы в одну матрицу, но я разбиваю вывод таким образом, что мы заполняем только те места, которые не были пустыми.

С вашими тестовыми данными я сопоставляю то, что вы получаете:

>> out_final

out_final =

    1.0000    1.0000         0    1.0000    1.0000
    1.0000    1.5000         0    3.0000    1.0000
    1.0000    2.0000         0    5.0000    1.0000

Однако, если я могу быть честным - если вы точно знаете, что у вас будет только три значения для accumarray, может быть быстрее просто вызвать его три раза, а затем объединить все, когда вы закончите. Я бы сказал, что это более читабельно и очень ясно дает понять, что вы делаете. Чтобы сделать это так, как я делал с массивом ячеек выше, вам нужно знать, как работает MATLAB.

Другие вопросы по тегам