2014-12-21 2 views
3

Matrix에 따라 Matlab에서 문제가 발생합니다. for 루프를 제거하면 코드가 향상 될 수 있다고 생각합니다. 그러나 나는 이것을 고치는 법을 정말로 모른다. 아무도 도와 줄 수 없니? 코드는이 코드행렬 계산에서 for 루프를 제거하는 matlab

K = 3; 
X = [1 2; 3 4; 5 6; 7 8]; 
idx = [1;2;3;1]; 
for i = 1:K 
    ids = (idx == i); 
    centroids(i,:) = sum(bsxfun(@times, X, ids))./ sum(ids); 
end 

, 데이터 포인트는 4 × X이다. K = 3 도심이 있으므로 도심은 3x2의 행렬입니다. 이 코드는 데이터 포인트와 가장 가까운 센트로이더를 사용하여 센티 우드의 새로운 위치를 찾는 K-mean 함수의 일부입니다. 나는 아마 다음과 같이 시작 FOR 루프없이 무언가로 코드를 만들고 싶어 :

ids = bsxfun(@eq, idx, 1:K); 
centroids = .............. 

답변

4

당신은 논리적 색인을 사용하여 bsxfun을 방지 할 수 있습니다, 이것은 적어도 작은 행렬 X에 대한 가치 성능 향상 될 것으로 보인다. K은 작고 X은 적은 수의 행에 적합합니다. X는 많은 수의 행이있는 경우

K = 3; 
X = [1 2; 3 4; 5 6; 7 8]; 
idx = [1;2;3;1]; 
centroids=zeros(K,2); 
for i = 1:K 
    ids = (idx == i); 
    centroids(i,:) = sum(X(ids,:),1)./sum(ids); 
end 

,이 방법은 가장 빠른 :

K = 3; 
X = [1 2; 3 4; 5 6; 7 8]; 
idx = [1;2;3;1]; 
centroids=zeros(K,2); 
t=bsxfun(@eq,idx,1:K); 
centroids=bsxfun(@rdivide,t.'*X,sum(t).'); 

그리고 K 경우

이 매우 큰, 루이스 ' accumarray 방법이 가장 빠르다.

+0

잘 보입니다. 여기에'bsxfun'이 필요 없습니다. –

+0

좋은 해결책입니다. 'centroid'를 미리 할당하는 것을 잊지 마세요 – Daniel

+0

@Daniel 물론! 큰'X' 행렬에 대해 더 빠른'bsxfun' 솔루션을 추가했습니다. – David

4

당신은 accumarray을 적용 할 수 있습니다. accumarrayX이 열일 경우에만 작동합니다. 그래서, X 경우 두 개의 열을 가지고, 두 번 accumarray를 호출 할 수 있습니다 : 또는

centroids(:,1) = accumarray(idx, X(:,1), [], @mean) 
centroids(:,2) = accumarray(idx, X(:,2), [], @mean) 

X실수의 두 개의 열이 포함되어있는 경우, 하나 개의 단지로 complex에 "팩"두 열을 사용할 수 있습니다 X 컬럼, P의 임의 수있는 경우

centroids = accumarray(idx, complex(X(:,1),X(:,2)), [], @mean); 
centroids = [ real(centroids) imag(centroids)]; 

: 열은 다음 결과를 풀고 ossibly 복소수과 함께, 당신은 열 이상 반복 할 수 있습니다

centroids = NaN(K, size(X,2)); %// preallocate 
for col = 1:size(X,2); 
    centroids(:,col) = accumarray(idx, X(:,col), [], @mean); 
end 
+0

이 방법은 'K'가 클 경우 특히 유용합니다. – David

+0

@David 루프 오버 인덱스를 루프 오버 인덱스로 대체하기 때문에 의미가 있습니다. 너는 몇 가지 테스트를 했니? –

+0

나는 거친 물건 몇 개만 만들었지 만, 당신의 설명이 의미가 있습니다. – David