MATLAB에서 행렬의 모든 행 / 열에 함수를 적용하려면 어떻게해야합니까?


106

예를 들어라고 말하여 벡터의 모든 항목에 함수를 적용하거나 함수를 v + 1사용할 수 있습니다 arrayfun. for 루프를 사용하지 않고 행렬의 모든 행 / 열에 대해 어떻게 할 수 있습니까?

답변:


73

많은 같은 작업을 내장 sum하고 prod이미이 이용하기 위해 적용하는 기능을 리팩토링 할 수 있습니다 있도록 행이나 열에서 작동 할 수 있습니다.

그 실행 가능한 옵션이 아닌 경우, 하나의 방법은 사용 세포에 행 또는 열을 수집하는 것입니다 수행하는 mat2cell또는 num2cell다음 사용, cellfun결과 셀 어레이에서 작동 할 수 있습니다.

예를 들어 행렬의 열을 합산한다고 가정 해 보겠습니다 M. 다음을 사용하여 간단히 수행 할 수 있습니다 sum.

M = magic(10);           %# A 10-by-10 matrix
columnSums = sum(M, 1);  %# A 1-by-10 vector of sums for each column

더 복잡한 num2cell/ cellfun옵션을 사용하여이 작업을 수행하는 방법은 다음과 같습니다 .

M = magic(10);                  %# A 10-by-10 matrix
C = num2cell(M, 1);             %# Collect the columns into cells
columnSums = cellfun(@sum, C);  %# A 1-by-10 vector of sums for each cell

17
나는 행렬을 셀형 배열로 변환하는 것보다 더 빠를 수있는 간단한 for 루프에 대해 특정 경우에 대해이 접근 방식의 성능을 테스트 할 것입니다. tic / tac 랩을 사용하여 테스트합니다.
yuk

5
@yuk : "tic / toc"을 의미하는 것 같아요. ;)
gnovice

4
@gnovice, 아마도 yuk이 약간의 마술을하고 tak = toc를 할당했습니다. true = false유효한 진술이 있는 언어에서 , 당신이 그것을 할 수있는 방법이 있다고 확신합니다 (:
chessofnerd

1
@Argyll : 어떤 접근 방식이 더 효율적인지 결정하는 것은 적용하려는 기능의 종류, 매트릭스의 크기 등에 따라 달라집니다. 요컨대 문제에 따라 달라질 수 있습니다. 사실, 때때로 좋은 오래된 for 루프가 가장 빠른 선택이 될 수 있습니다.
gnovice 2014

2
@gnovice, 나는에 편집을 제안한다 sum(M, 1). 초보자는 sum임의의 크기의 행렬에 대해 이런 식으로 사용할 수 있다고 생각한 다음 행렬이 1-by-n.
스튜이 그리핀

24

좀 더 모호한 Matlab 함수 bsxfun을 원할 수 있습니다 . Matlab 문서에서 bsxfun은 "함수 핸들 fun에 의해 지정된 요소 별 이진 연산을 단일 확장이 활성화 된 배열 A와 B에 적용합니다."

@gnovice는 sum 및 기타 기본 함수가 이미 첫 번째 비단 일 차원 (즉, 행이 둘 이상인 경우 행, 행이 하나만있는 경우 열, 더 낮은 차원이 모두 size == 1 인 경우 더 높은 차원)에서 이미 작동한다고 명시했습니다. ). 그러나 bsxfun은 (특히) 사용자 정의 함수를 포함한 모든 함수에서 작동합니다.

예를 들어 행렬 A와 행 벡터 BEg가 있다고 가정 해 보겠습니다.

A = [1 2 3;
     4 5 6;
     7 8 9]
B = [0 1 2]

A의 모든 요소를 ​​B의 해당 열의 거듭 제곱으로 벡터 C에서 반환하는 함수 power_by_col을 원합니다.

위의 예에서 C는 3x3 행렬입니다.

C = [1^0 2^1 3^2;
     4^0 5^1 6^2;
     7^0 8^1 9^2]

즉,

C = [1 2 9;
     1 5 36;
     1 8 81]

repmat을 사용하여 무차별 대입 방식으로 수행 할 수 있습니다.

C = A.^repmat(B, size(A, 1), 1)

또는 내부적으로 repmat 단계를 처리하는 bsxfun을 사용하여 고급 방식으로 수행 할 수 있습니다.

C = bsxfun(@(x,y) x.^y, A, B)

따라서 bsxfun은 몇 가지 단계를 절약합니다 (A의 차원을 명시 적으로 계산할 필요가 없음). 그러나 내 일부 비공식 테스트에서 적용 할 기능 (위의 내 힘 기능과 같이)이 간단하다면 repmat이 대략 두 배 빠른 것으로 나타났습니다. 따라서 단순성 또는 속도를 원하는지 선택해야합니다.


21

이것이 얼마나 효율적인지에 대해서는 언급 할 수 없지만 여기에 해결책이 있습니다.

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :))
applyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1))'

% Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @sum;

applyToRows(myFunc, myMx)

보다 일반적인 대답은 여기에 있습니다 .
Wok

11

바탕 알렉스의 대답은 여기에서 더 일반적인 기능은 다음과 같습니다

applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :));
newApplyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1), 'UniformOutput', false)';
takeAll = @(x) reshape([x{:}], size(x{1},2), size(x,1))';
genericApplyToRows = @(func, matrix) takeAll(newApplyToRows(func, matrix));

다음은 두 기능을 비교 한 것입니다.

>> % Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @(x) [mean(x), std(x), sum(x), length(x)];
>> genericApplyToRows(myFunc, myMx)

ans =

     2     1     6     3
     5     1    15     3
     8     1    24     3

>> applyToRows(myFunc, myMx)
??? Error using ==> arrayfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false.

Error in ==> @(func,matrix)arrayfun(applyToGivenRow(func,matrix),1:size(matrix,1))'


4

r2016b부터 시작하여이 질문에 대한 답변의 진화하는 특성에 추가하여 MATLAB은 암시 적으로 단일 차원을 확장 bsxfun하여 많은 경우에 대한 필요성을 제거합니다 .

로부터 r2016b 릴리스 정보 :

암시 적 확장 : 길이 1의 차원을 자동으로 확장하여 배열에 요소 별 연산 및 함수 적용

암시 적 확장은 스칼라 확장의 일반화입니다. 스칼라 확장을 사용하면 스칼라가 다른 배열과 동일한 크기로 확장되어 요소 별 연산을 용이하게합니다. 암시 적 확장을 사용하면 여기에 나열된 요소 별 연산자 및 함수는 배열의 크기가 호환되는 한 암시 적으로 입력을 동일한 크기로 확장 할 수 있습니다. 모든 차원에 대해 입력의 차원 크기가 같거나 그 중 하나가 1 인 경우 두 배열의 크기가 호환됩니다. 자세한 내용은 기본 연산 및 배열 대 행렬 연산을위한 호환 가능한 배열 크기를 참조하세요.

Element-wise arithmetic operators+, -, .*, .^, ./, .\

Relational operators<, <=, >, >=, ==, ~=

Logical operators&, |, xor

Bit-wise functionsbitand, bitor, bitxor

Elementary math functionsmax, min, mod, rem, hypot, atan2, atan2d

예를 들어 행렬 A에서 각 열의 평균을 계산 한 다음 A-mean (A)을 사용하여 각 열에서 평균 값 벡터를 뺄 수 있습니다.

이전에는이 ​​기능을 bsxfun 함수를 통해 사용할 수있었습니다. 이제 대부분의 bsxfun 사용을 암시 적 확장을 지원하는 함수 및 연산자에 대한 직접 호출로 바꾸는 것이 좋습니다. bsxfun을 사용하는 것에 비해 암시 적 확장은 더 빠른 속도, 더 나은 메모리 사용 및 향상된 코드 가독성을 제공합니다.


2

위의 답변 중 어느 것도 나에게 "즉시"작동하지 않았지만 다른 답변의 아이디어를 복사하여 얻은 다음 기능이 작동합니다.

apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));

함수 f를 사용하여 행렬의 모든 열에 적용합니다 M.

예를 들면 다음과 같습니다.

f = @(v) [0 1;1 0]*v + [0 0.1]';
apply_func_2_cols(f,[0 0 1 1;0 1 0 1])

 ans =

   0.00000   1.00000   0.00000   1.00000
   0.10000   0.10000   1.10000   1.10000

1

최신 버전의 Matlab을 사용하면 Table 데이터 구조를 유리하게 사용할 수 있습니다. 'rowfun'작업도 있지만 이렇게하는 것이 더 쉽다는 것을 알았습니다.

a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))

또는 이전 Matlab 버전의 경우 테이블이 필요하지 않은 이전 버전이 있습니다.

dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')

1

허용되는 대답은 먼저 셀로 변환 한 다음 cellfun모든 셀에서 작동 하는 데 사용 하는 것 같습니다 . 특정 응용 프로그램을 모르지만 일반적으로 bsxfun매트릭스를 사용 하는 것이 더 효율적 이라고 생각 합니다. 기본적으로 bsxfun두 배열에 요소별로 작업을 적용합니다. 따라서 n x 1벡터의 각 항목에 벡터의 각 항목을 곱하여 배열 m x 1을 얻으려면 n x m다음을 사용할 수 있습니다.

vec1 = [ stuff ];    % n x 1 vector
vec2 = [ stuff ];    % m x 1 vector
result = bsxfun('times', vec1.', vec2);

이렇게하면 result(i, j) 항목이의 i 번째 요소 vec1에의 j 번째 요소를 곱한 행렬이 제공 됩니다 vec2.

당신이 사용할 수있는 bsxfun기능에 내장 된 모든 종류의, 당신은 당신의 자신을 선언 할 수 있습니다. 문서에는 많은 내장 함수 목록이 있지만 기본적으로 두 배열 (벡터 또는 행렬)을 인수로 받아들이는 함수의 이름을 지정하고 작동하도록 할 수 있습니다.


-1

행렬의 행 합계를 계산하는 방법을 찾는 동안이 질문 / 답변을 우연히 발견했습니다.

Matlab의 SUM 함수가 실제로 주어진 차원, 즉 2 차원이있는 표준 행렬에 대한 합계를 지원한다는 것을 추가하고 싶습니다.

따라서 열 합계를 계산하려면 다음을 수행하십시오.

colsum = sum(M) % or sum(M, 1)

행 합계의 경우 간단히

rowsum = sum(M, 2)

내 생각은 이것이 for 루프를 프로그래밍하고 셀로 변환하는 것보다 빠르다는 것입니다. :)

이 모든 것은 SUM에 대한 MATLAB 도움말에서 찾을 수 있습니다.


7
주어진 차원에 따라 SUM을 적용하는 기능은이 질문에 대한 원래 답변의 첫 번째 문장에서 언급되었습니다. 그런 다음 차원을 선택할 수있는 기능이 함수에 아직 내장되어 있지 않은 경우에 대한 답변이 계속되었습니다. 하지만 내장 된 차원 선택 옵션을 사용하는 것이 (사용 가능한 경우) 거의 항상 for 루프 나 셀로 변환하는 것보다 빠릅니다.
cjh

그러나 위의 대답은 내가 그 모든 공상이 필요하지 않았기 때문에 나를 다시 matlab 문서로 보냈으므로 간단한 해결책이 필요한 다른 사람들을 검색에서 공유하고 저장하고 싶었습니다.
nover

-2

행의 길이를 알고 있다면 다음과 같이 만들 수 있습니다.

a=rand(9,3);
b=rand(9,3); 
arrayfun(@(x1,x2,y1,y2,z1,z2) line([x1,x2],[y1,y2],[z1,z2]) , a(:,1),b(:,1),a(:,2),b(:,2),a(:,3),b(:,3) )

2
이 대답을 보는 사람에게 : 이것은 그렇게하는 방법이 아닙니다! 이것은 MATLAB에서 어떤 작업도 수행하는 방법이 아닙니다!
Stewie Griffin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.