Pergunta

Eu quero aplicar uma função para todas as colunas em uma matriz com MATLAB. Por exemplo, eu gostaria de ser capaz de chamar suave em cada coluna de uma matriz, em vez de ter deleite suave a matriz como um vetor (que é o comportamento padrão se você chamar smooth(matrix)).

Eu tenho certeza que deve haver uma maneira mais idiomática de fazer isso, mas eu não posso encontrá-lo, para que eu tenha definido uma função map_column:

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

que eu posso chamar com:

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

Existe errado nada com esse código? Como eu poderia melhorá-lo?

Foi útil?

Solução

A sua solução é bom.

Note que horizcat cobra uma penalidade de desempenho substancial para grandes matrizes. Ele faz com que o código seja O (N ^ 2), em vez de O (N). Para uma matriz 100x10,000, sua implementação leva 2.6s na minha máquina, o horizcat um leva 64.5s. Para uma matriz 100x5000, a implementação horizcat leva 15.7s.

Se você quiser, você pode generalizar a sua função um pouco e torná-lo capaz de interagir sobre a dimensão final ou até mesmo dimensões mais arbitrárias (e não apenas colunas).

Outras dicas

O MATLAB declaração "for" realmente faz um loop sobre as colunas de tudo o que é fornecido - Normalmente, isso só resulta em uma sequência de escalares desde o vetor passado em para (como no seu exemplo acima) é um vetor linha. Isso significa que você pode reescrever o código acima assim:

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

Se func não retorna um vetor coluna, então você pode adicionar algo como

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

para forçá-lo em uma coluna.

Talvez você sempre pode transformar a matriz com o 'operador e, em seguida, transformar a volta resultado.

smoothed = smooth(input', 9)';

que pelo menos trabalhos com a função FFT.

Uma maneira de fazer com que um loop implícito entre as colunas de uma matriz consiste em utilizar cellfun. Ou seja, você deve primeiro converter a matriz para uma matriz de células, cada célula vai realizar uma coluna. Em seguida, chamar cellfun. Por exemplo:

A = randn(10,5);

Veja que aqui eu tenho calculado o desvio padrão para cada coluna.

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

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482

Claro que, muitas funções no MATLAB já estão configurados para trabalhar em linhas ou colunas de uma matriz como o usuário indica. Isto é verdade para std é claro, mas esta é uma maneira conveniente de teste que cellfun trabalhado com sucesso.

std(A,[],1)

ans =
      0.78681       1.1473      0.89789      0.66635       1.3482

Não se esqueça de pré-alocar a matriz resultado se você está lidando com grandes matrizes. Caso contrário, sua CPU vai gastar lotes de ciclos repetidamente re-alocar a matriz cada vez que acrescenta uma nova linha / coluna.

Se este é um caso de uso comum para a sua função, talvez fosse uma boa idéia para fazer a função iterate através das colunas automaticamente se a entrada não é um vetor.

Isto não exatamente resolver o seu problema, mas seria simplificar o uso das funções. Nesse caso, a saída deve ser uma matriz, também.

Você também pode transformar a matriz para uma longa coluna usando m(:,:) = m(:). No entanto, isso depende da sua função se isso faria sentido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top