2
votes

Rechercher un tableau autour des valeurs maximales d'un tableau

J'ai ici une question assez compliquée sur laquelle je travaille. C'est extrêmement difficile à décrire avec des mots, alors je vais essayer de l'expliquer avec un exemple.

Supposons que j'ai une matrice de valeurs:

Desired_Matrix =

 [12 36 36 33 18]
 [67 85 84 71 57]
 [35 33 13 39 51]

Maintenant, je veux d'abord trouver un vecteur maximum dans la première dimension, ce qui est facile:

XXX

Maintenant je veux obtenir une matrice "amincie" avec des valeurs autour des maxima (indices périodiques):

[max_vector,~] = max(A,[],1);


max_vector=[67,85, 84, 71,57]

Ceci est la matrice avec les vecteurs autour des valeurs maximales de la matrice A. Quelqu'un peut-il me dire comment faire cela sans utiliser une boucle double for?

Merci!


1 commentaires

Vous avez de très bonnes réponses à cette question, envisagez d'en accepter une . Je suggère cela parce que vous avez plusieurs questions avec des réponses, mais que vous n'avez jamais accepté de réponse, peut-être que vous n'étiez pas au courant de la possibilité. Vous n'êtes pas obligé d'accepter, mais c'est considéré comme une bonne pratique.


5 Réponses :


4
votes

La réponse de @ HansHirse est plus efficace, car elle ne crée pas de matrice intermédiaire.


Essayez ceci:

[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = ind_max + (0:2).' + (0:size(A_ext,2)-1)*size(A_ext,1);
result = reshape(A_ext(ind_lin), 3, []);

Pour Matlab R2016b ou plus récent, vous pouvez simplifier la troisième ligne:

[~, ind_max] = max(A,[],1);
A_ext = A([end 1:end 1],:);
ind_lin = bsxfun(@plus, bsxfun(@plus, ind_max, (0:2).'), (0:size(A_ext,2)-1)*size(A_ext,1));
result = reshape(A_ext(ind_lin), 3, []);


0 commentaires

5
votes
% Input.
A = [31 85 36 71 51; 12 33 74 39 12; 67 11 13 14 18; 35 36 84 33 57]

% Dimensions needed.
nRows = size(A, 1);
nCols = size(A, 2);

% Get maxima and corresponding indices in input.
[max_vector, ind] = max(A);

% Get neighbouring indices.
ind = [ind - 1; ind; ind + 1];

% Modulo indices to prevent dimension overflow.
ind = mod(ind, nRows);

% Correct zero indices.
ind(ind == 0) = nRows;

% Calculate correct indices in A.
temp = repmat(0:nRows:nRows*(nCols-1), 3, 1);
ind = ind + temp;

% Output.
B = A(ind)
Since we have max indices per column, but later want to access these elements in the original array A, we need proper linear indices for A. Here, the trick is to add the number of rows multiplied by the column index (starting by 0). The easiest way to understand might be to remove the semicolons, and inspect the intermediate values of ind.

5 commentaires

J'aime votre idée d'indexation modulaire


Je ne comprends pas la ligne: temp = repmat (0: nRows: nRows ^ 2, 3, 1); Pouvez-vous me dire ce que cela fait?


Vous avez une erreur mathématique mineure - 0: nRows: nRows ^ 2 se trouve être seulement la taille correcte car dans cet exemple size (A, 2) - 1 == size (A , 1) . Il doit être 0: nRows: nRows * nCols-1


@Wolfie Merci pour la correction, j'ai édité ma réponse en conséquence. Quelle stupidité, puisque dans mon explication textuelle, je l'ai décrit exactement de cette façon. Une correction mineure à votre correction: 0: nRows: nRows * (nCols-1) au lieu de 0: nRows: nRows * nCols-1 . Les deux fonctionnent, mais «absolument correct» devrait être la version entre parenthèses.


Les deux fonctionneront exactement de la même manière. Créer un tableau avec la notation 0: x: y , chaque élément ni est x * i , tel que ni . Avec et sans parenthèses, nous avons la même valeur supérieure possible pour x * i je pense. Dans votre cas, la valeur supérieure possible et y sont égaux, dans mon cas je me fie à l'évaluation par MATLAB du strict <. Préférence personnelle qui a plus de sens je pense - je savais juste que sans le -1 j'inclurais une valeur de trop, vous connaissiez la valeur que vous visiez.



3
votes

Voici une autre solution. Ceci est similaire à la réponse de HansHirse , avec deux améliorations:

  • Gère un peu plus élégamment l'indexation modulaire
  • Est plus flexible pour spécifier les voisins de votre choix

Code:

% Input
A = [31 85 36 71 51; 
    12 33 74 39 12; 
    67 11 13 14 18; 
    35 36 84 33 57];

% Relative rows of neighbours, i.e. this is [-1, 0, 1] for +/- one row
p = -1:1;
% Get A row and column counts for ease
[nr, nc] = size(A);
% Get max indices
[~,idx] = max( A, [], 1 );
% Handle overflowing indices to wrap around rows
% You don't have to redefine "idx", could use this directly in the indexing line
idx = mod( idx + p.' - 1, nr ) + 1;
% Output B. The "+ ... " is to convert to linear indices, as "idx"
% currently just refers to the row number.
B = A(idx + (0:nr:nr*nc-1));


0 commentaires

0
votes

Vous pouvez utiliser la boîte à outils de traitement d'image pour générer le résultat, bien que ce soit moins efficace que d'autres solutions.

[~,idx] = max(A, [], 1);
d = imdilate( idx == (1:size(A,1) ).', [1;1;1], 'full');
p = padarray(A, 1, 'circular');
Desired_Matrix = reshape(p(d), 3, []);


0 commentaires

0
votes

juste pour votre information, voici le formulaire généralisé pour le 3D-Case:

A = zeros(3,5,5);

for id = 1: 20
    A(:,:,id) = id;


    if id == 10
        A(:,:,id) = 100;
    end

end


% Relative rows of neighbours, i.e. this is [-1, 0, 1] for +/- one row
p = -1:1;
% Get A row and column counts for ease
[nr, nc, nz] = size(A);
% Get max indices
[~,idx] = max( A, [], 3 );
% Handle overflowing indices to wrap around rows
% You don't have to redefine "idx", could use this directly in the indexing line
idx = mod( idx + reshape(p,1,1,3) - 1, nz ) + 1;
% Output B. The "+ ... " is to convert to linear indices, as "idx"
% currently just refers to the row number.

INDICES = ((idx-1) * (nr*nc)+1 )+ reshape(0:1:nc*nr-1,nr,nc);

B = A(INDICES);


0 commentaires