MATLAB에서 n 차원 행렬의 각 요소를 어떻게 반복합니까?


87

문제가 있습니다. MATLAB에서 n 차원 행렬의 모든 요소를 ​​반복해야합니다. 문제는 임의의 차원에 대해이 작업을 수행하는 방법을 모른다는 것입니다. 내가 말할 수 있다는 걸 알아

for i = 1:size(m,1)
    for j = 1:size(m,2)
        for k = 1:size(m,3)

등등, 그러나 임의의 수의 차원에 대해 수행하는 방법이 있습니까?


13
Matlab 용어 참고 : Matlab에는 소수의 핵심 데이터 유형이 있습니다. 가장 중요한 것은 구조체, 행렬, 셀형 배열입니다. 행렬의 일부를 참조 할 때 "요소"라는 용어를 사용하고 셀형 배열의 일부를 참조하기 위해 "셀"이라는 용어를 예약하는 것이 일반적입니다. 셀형 배열과 행렬은 둘 다 N 차원 데이터 구조 임에도 불구하고 수많은 구문 및 의미 론적 차이가 있습니다.
Mr Fooz

3
반복이 필요한 것이 무엇인지 물어봐도 될까요? 대신 "벡터화 된"방법이있을 수 있습니다.
Hosam Aly

답변:


92

선형 인덱싱을 사용하여 각 요소에 액세스 할 수 있습니다.

for idx = 1:numel(array)
    element = array(idx)
    ....
end

이것은 i, j, k, 현재 상태를 알 필요가없는 경우에 유용합니다. 그러나 현재 어떤 인덱스에 있는지 알 필요가 없다면 arrayfun ()을 사용하는 것이 좋습니다.


1
또한 어떤 이유로 인덱스를 복구하려는 경우에도 다음 두 가지 간단한 명령을 사용할 수 I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);있습니다..
knedlsepp 2015 년

34

MATLAB에서 배열에 대한 선형 인덱스의 개념은 중요한 것입니다. MATLAB의 배열은 실제로 메모리에 묶인 요소의 벡터 일뿐입니다. MATLAB에서는 행 및 열 인덱스 또는 단일 선형 인덱스를 사용할 수 있습니다. 예를 들면

A = magic(3)
A =
     8     1     6
     3     5     7
     4     9     2

A(2,3)
ans =
     7

A(8)
ans =
     7

배열을 벡터로 풀어서 요소가 메모리에 저장되는 순서를 볼 수 있습니다.

A(:)
ans =
     8
     3
     4
     1
     5
     9
     6
     7
     2

보시다시피 8 번째 요소는 숫자 7입니다. 실제로 find 함수는 결과를 선형 인덱스로 반환합니다.

find(A>6)
ans =
     1
     6
     8

결과적으로 단일 루프를 사용하여 일반 nd 배열의 각 요소에 차례로 액세스 할 수 있습니다. 예를 들어 A의 요소를 제곱하려는 경우 (예, 더 나은 방법이 있다는 것을 알고 있습니다) 다음과 같이 할 수 있습니다.

B = zeros(size(A));
for i = 1:numel(A)
  B(i) = A(i).^2;
end

B
B =
    64     1    36
     9    25    49
    16    81     4

선형 인덱스가 더 유용한 상황이 많이 있습니다. 선형 인덱스와 2 차원 (또는 더 높은) 첨자 간의 변환은 sub2ind 및 ind2sub 함수를 사용하여 수행됩니다.

선형 인덱스는 일반적으로 matlab의 모든 배열에 적용됩니다. 따라서 구조체, 셀형 배열 등에 사용할 수 있습니다. 선형 인덱스의 유일한 문제는 너무 커질 때입니다. MATLAB은 32 비트 정수를 사용하여 이러한 인덱스를 저장합니다. 따라서 배열에 총 2 ^ 32 개 이상의 요소가있는 경우 선형 인덱스는 실패합니다. 희소 행렬을 자주 사용하는 경우에만 문제가됩니다. 가끔 이로 인해 문제가 발생합니다. (64 비트 MATLAB 릴리스를 사용하지 않지만, 운이 좋은 사람들을 위해 문제가 해결되었다고 생각합니다.)


64 비트 MATLAB의 인덱싱은 실제로 64 비트 첨자를 올바르게 허용합니다. 예 : x = ones(1,2^33,'uint8'); x(2^33)예상대로 작동합니다.
Edric

@Edric-물론 이것은 내가 그 진술을 한 이후 몇 년 동안 (그리고 많은 릴리스에서) 확실히 변경되었을 행동입니다. 그래도 확인해 주셔서 감사합니다.

:) 제가 댓글을 달기 전까지는 답변이 얼마나 오래되었는지 몰랐습니다. 질문이 RSS 피드에 방금 나타 났고 제가 답변을 했는지도 몰랐습니다!
Edric 2011

15

몇 가지 다른 답변에서 지적했듯이 단일 for 루프 에서 to to 까지 선형 인덱스A사용하여 (모든 차원의) 행렬의 모든 요소를 ​​반복 할 수 있습니다 . 또한 사용할 수있는 몇 가지 기능이 있습니다. 및 .1numel(A)arrayfuncellfun

먼저 A(라고하는 my_func) 의 각 요소에 적용하려는 함수가 있다고 가정 해 보겠습니다 . 먼저이 함수에 대한 함수 핸들 을 만듭니다 .

fcn = @my_func;

경우 A(두 번 등, 단일 유형의) 임의의 차원의 매트릭스를, 당신은 사용할 수 있습니다 arrayfun적용하는 my_func각 요소 :

outArgs = arrayfun(fcn, A);

경우 AA는 셀 어레이 임의의 차원, 당신은 사용할 수 있습니다 cellfun적용 할 my_func각 셀에 :

outArgs = cellfun(fcn, A);

함수 my_funcA입력 으로 받아 들여야 합니다. 의 출력이 있으면 my_func에 배치 outArgs되며 A.

만약 출력에 한 가지주의 ... my_func다른 크기 및 형태의 반환 출력은 다른 요소에서 동작 할 때 A, 다음 outArgs세포 배열로 만들 수있을 것이다. 이것은 어느 쪽인지를 호출하여 수행됩니다 arrayfun또는 cellfun추가 매개 변수 / 값 쌍 :

outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);

13

또 다른 트릭은 ind2subsub2ind. 와 결합 numel하고 size, 이것은이 N 차원 배열을 생성하고 1 일 위해 "대각선"에있는 모든 요소를 설정 다음, 같은 것들을 수행 할 수있다.

d = zeros( 3, 4, 5, 6 ); % Let's pretend this is a user input
nel = numel( d );
sz = size( d );
szargs = cell( 1, ndims( d ) ); % We'll use this with ind2sub in the loop
for ii=1:nel
    [ szargs{:} ] = ind2sub( sz, ii ); % Convert linear index back to subscripts
    if all( [szargs{2:end}] == szargs{1} ) % On the diagonal?
        d( ii ) = 1;
    end
end

+1은 MATLAB이 덕 타이핑을 중단하는 방법에 대한 좋은 예를 보여줍니다.
Phillip Cloud

1

재귀 함수를 만들 수 있습니다.

  • 허락하다 L = size(M)
  • 허락하다 idx = zeros(L,1)
  • 타고 length(L)최대 깊이로
  • 고리 for idx(depth) = 1:L(depth)
  • 깊이가 length(L)이면 요소 연산을 수행하고 그렇지 않으면 다음을 사용하여 함수를 다시 호출하십시오.depth+1

모든 포인트를 확인하려는 경우 벡터화 된 방법만큼 빠르지는 않지만 대부분의 포인트를 평가할 필요가 없다면 시간을 상당히 절약 할 수 있습니다.


1

이러한 솔루션은 사용하는 것보다 더 빠릅니다 (약 11 %) numel.

for idx = reshape(array,1,[]),
     element = element + idx;
end

또는

for idx = array(:)',
    element = element + idx;
end

UPD. 마지막 답변에서 감지 된 오류에 대한 tnx @rayryeng


부인 성명

이 게시물이 참조 한 타이밍 정보는 근본적인 오타로 인해 부정확하고 정확하지 않습니다 (아래 댓글 스트림과 편집 기록 참조 -특히이 답변의 첫 번째 버전을 확인하십시오). 경고 Emptor .


1
1 : array(:)와 동일합니다 1 : array(1). 이것은 모든 요소를 ​​반복하지 않으므로 런타임이 빠릅니다. 또한 부동 소수점 숫자를 rand생성 하므로 명령문이 초기 값이 1 인 증가 벡터를 찾고 끝 값 이 증가 하는 범위 가 1을 제외한 부동 소수점 숫자로 끝나는 벡터를 찾으려고 할 때 빈 배열이 생성됩니다. 1의 단계. 이러한 가능한 벡터가 없으므로 빈 벡터가 생성됩니다. 귀하의 루프가 실행되지 않습니다, 그래서 당신의 주장은 거짓입니다. -1 표. 죄송합니다. 1 : array(:)[0,1)for
rayryeng 2015

@rayryeng 당신이 옳지 않습니다. array (:)는 1 : array (1)과 동일하지 않습니다. 좋아해요 reshape(...).
mathcow apr

@rayryeng matlab r2013a + linux-작동합니다! ;) 난 그냥 그 코드가 너무 실행
mathcow

1 : array(:)를 만든 후 명령 프롬프트 에 on 을 입력 합니다 array . 빈 행렬을 얻습니까? 그렇다면 코드가 작동하지 않습니다. 당신이 허위 정보를 제공했기 때문에 나는 내 투표를 떠납니다.
rayryeng 2015-04-09

@rayryeng 나는 이해하고있다! 그래, 당신이 바로 어리석은 분쟁 죄송합니다
mathcow

-1

의 다른 용도를 더 자세히 살펴보면 size실제로 각 차원 크기의 벡터를 얻을 수 있음을 알 수 있습니다. 이 링크는 문서를 보여줍니다.

www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html

크기 벡터를 얻은 후 해당 벡터를 반복합니다. 다음과 같은 것 (대학 때부터 Matlab을 사용하지 않았으므로 내 구문을 용서하십시오) :

d = size(m);
dims = ndims(m);
for dimNumber = 1:dims
   for i = 1:d[dimNumber]
      ...

이것을 실제 Matlab-legal 구문으로 만들면 원하는 것을 할 것이라고 생각합니다.

또한 여기에 설명 된대로 선형 인덱싱을 수행 할 수 있어야합니다 .


루프의 순서가 행렬의 모든 요소에서 어떻게 반복되는지 잘 모르겠습니다. 예를 들어 3x4 행렬 (요소 12 개 포함)이있는 경우 내부 루프는 7 번만 반복됩니다.
gnovice

행렬의 각 차원을 반복해야합니다. 외부 루프는 차원을 반복하고 내부 루프는 해당 차원의 크기를 반복합니다. 적어도 그것이 아이디어입니다. 다른 모든 사람들이 말했듯이 그가 원하는 것이 각 셀이면 라이너 인덱싱이 가장 좋습니다. 각 차원을 반복하려면 이와 비슷한 작업을 수행해야합니다.
Erich Mirabal

또한 편집 해 주셔서 감사합니다. 내 링크는 다소 복잡했고 일반적인 링크 방식을 사용하면 제대로 작동하지 않습니다. 또한, 내 진술을 확장하기 위해 : 그는 여전히 많은 다른 인덱스 추적을 수행해야합니다 (카운터 또는 이와 유사한 것을 사용). 당신이나 앤드류의 접근 방식이 그가하려는 일에 대해 더 쉬울 것이라고 생각합니다.
Erich Mirabal

-1

n-nested for 루프를 시뮬레이션하려고합니다.

n 차원 배열을 반복하는 것은 n 자리 숫자를 증가시키는 것으로 볼 수 있습니다.

각 차원에서 우리는 차원의 길이만큼 자릿수를가집니다.

예:

array (matrix)가 있다고 가정합니다.

int[][][] T=new int[3][4][5];

"for notation"에는 다음이 있습니다.

for(int x=0;x<3;x++)
   for(int y=0;y<4;y++)
       for(int z=0;z<5;z++)
          T[x][y][z]=...

이를 시뮬레이션하려면 "n 자리 숫자 표기법"을 사용해야합니다.

첫 번째는 3 자리, 두 번째는 4 자리, 세 번째 자리는 5 자리 숫자입니다.

숫자를 늘려야하므로 시퀀스를 얻을 수 있습니다.

0 0 0
0 0 1
0 0 2    
0 0 3
0 0 4
0 1 0
0 1 1
0 1 2
0 1 3
0 1 4
0 2 0
0 2 1
0 2 2
0 2 3
0 2 4
0 3 0
0 3 1
0 3 2
0 3 3
0 3 4
and so on

따라서 이러한 n 자리 숫자를 늘리는 코드를 작성할 수 있습니다. 숫자 값으로 시작하여 숫자로 숫자를 늘리거나 줄일 수있는 방식으로 할 수 있습니다. 이렇게하면 테이블 어딘가에서 시작하여 끝이 아닌 중첩 된 for 루프를 시뮬레이션 할 수 있습니다.

하지만 이것은 쉬운 일이 아닙니다. 나는 matlab 표기법을 불편하게 도울 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.