Каков наилучший способ перебора столбцов матрицы? - PullRequest
9 голосов
/ 19 октября 2008

Я хочу применить функцию ко всем столбцам в матрице с помощью MATLAB. Например, я хотел бы иметь возможность вызывать сглаживание для каждого столбца матрицы вместо того, чтобы сглаживать обработку матрицы как вектора (это поведение по умолчанию, если вы вызываете smooth(matrix)).

Я уверен, что должен быть более идиотский способ сделать это, но я не могу его найти, поэтому я определил функцию map_column:

function result = map_column(m, func)
    result = m;
    for col = 1:size(m,2)
        result(:,col) = func(m(:,col));
    end
end

по которому я могу позвонить:

smoothed = map_column(input, @(c) (smooth(c, 9)));

Что-то не так с этим кодом? Как я могу улучшить это?

Ответы [ 6 ]

9 голосов
/ 23 октября 2008

Оператор MATLAB «for» фактически проходит по столбцам того, что было предоставлено - обычно это просто приводит к последовательности скаляров, поскольку вектор, переданный в for (как в вашем примере выше), является вектором строки. Это означает, что вы можете переписать приведенный выше код следующим образом:

function result = map_column(m, func)
    result = [];
    for m_col = m
      result = horzcat(result, func(m_col));
    end

Если func не возвращает вектор столбца, вы можете добавить что-то вроде

f = func(m_col);
result = horzcat(result, f(:));

чтобы заставить его в столбец.

3 голосов
/ 09 ноября 2008

Ваше решение в порядке.

Обратите внимание, что horizcat требует значительного снижения производительности для больших матриц. Это делает код O (N ^ 2) вместо O (N). Для матрицы 100x10 000 ваша реализация занимает 2,6 с на моей машине, горизонтальная - 64,5 с. Для матрицы 100x5000 реализация horizcat занимает 15,7 с.

Если вы хотите, вы можете немного обобщить свою функцию и сделать так, чтобы она могла перебирать конечное измерение или даже произвольное измерение (не только столбцы).

2 голосов
/ 11 апреля 2009

Способ вызвать неявный цикл по столбцам матрицы - использовать cellfun. То есть сначала нужно преобразовать матрицу в массив ячеек, каждая ячейка будет содержать один столбец. Тогда позвоните в cellfun. Например:

A = randn(10,5);

Обратите внимание, что здесь я вычислил стандартное отклонение для каждого столбца.

cellfun(@std,mat2cell(A,size(A,1),ones(1,size(A,2))))

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482

Конечно, многие функции в MATLAB уже настроены для работы со строками или столбцами массива, как указывает пользователь. Это, конечно, верно для std, но это удобный способ проверить, что cellfun успешно работал.

std(A,[],1)

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482
2 голосов
/ 19 октября 2008

Возможно, вы всегда можете преобразовать матрицу с помощью оператора ', а затем преобразовать результат обратно.

smoothed = smooth(input', 9)';

Это как минимум работает с функцией fft.

1 голос
/ 10 декабря 2008

Не забудьте предварительно выделить матрицу результатов, если вы имеете дело с большими матрицами. В противном случае ваш ЦП будет тратить много циклов, многократно перераспределяя матрицу при каждом добавлении новой строки / столбца.

0 голосов
/ 19 октября 2008

Если это обычный вариант использования вашей функции, возможно, было бы неплохо сделать так, чтобы функция автоматически перебирала столбцы, если входные данные не являются вектором.

Это не совсем решит вашу проблему, но упростит использование функций. В этом случае на выходе также должна быть матрица.

Вы также можете преобразовать матрицу в один длинный столбец, используя m(:,:) = m(:). Тем не менее, от вашей функции зависит, будет ли это иметь смысл.

...