2017-05-30 2 views
2

La matrice A est ma matrice de départ qui contient les données enregistrées depuis mon MPU6050 et GPS sur une carte SD (Latitude, Longitude, Heure, Axe , Ay, Az, Gx, Gy, Gz).Meilleure façon d'extraire toutes les lignes d'une matrice A contenant un élément d'une matrice B

J'ai calculé l'écart-type de Az pour la taille de fenêtre de 5 et identifié tous les éléments qui satisfont une condition (> seuil).

Ensuite, dans une matrice "large_windows" j'ai stocké l'index de tous les Az dans la fenêtre qui satisfont la condition.

De matrice « large_windows » i calcule une nouvelle matrice B avec toutes les lignes de la matrice A qui contiennent la matrice « large_windows » éléments.

Je pense que mon code est effective, mais très laid et chaotique, plus je ne suis toujours pas très pratique avec indexing mais je veux apprendre.


1. Une meilleure solution existe-t-elle?


2. Il est possible d'utiliser une indexation logique? Comment? C'est efficace *?

Voici mon code, est un exemple simplifié, avec condition générique, de comprendre le concept mieux non seulement ma situation particulière, starting from suggestions of a previous problem(how to create a sliding window

%random matix nXm 
a=rand(100,6); 

%window dimension 
window_size=4; 

%overlap between two windows 
overlap=1; 

%increment needed 
step=window_size - overlap; 

%std threshold 
threshold=0.3; 
std_vals= NaN(size(a,1),1); 

%The sliding window will analyze only the 5th column 
for i=1: step: (size(a,1)-window_size) 
    std_vals(i)=std(a(i:(i+window_size-1),5)); 
end 

% finding the rows with standard deviation larger than threshold 
large_indexes = find(std_vals>threshold); 

%Storing all the elements that are inside the window with std>threshold 

large_windows = zeros(numel(large_indexes), window_size); 
for i=1:window_size 
    large_windows(:,i) = large_indexes + i - 1; 
end 

% Starting extracting all the rows with the 5th column outlier elements 
n=numel(large_windows); 

%Since i will work can't know how long will be my dataset 
%i need to knwo how is the "index distance" between two adjacent elements 
% in the same row [es. a(1,1) and a(1,2)] 


diff1=sub2ind(size(a),1,1); 
diff2=sub2ind(size(a),1,2); 

l_2_a_r_e = diff2-diff1 %length two adjacent row elements 
large_windows=large_windows' 
%calculating al the index of the element of a ith row containing an anomaly 
for i=1:n 

    B{i}=[a(large_windows(i))-l_2_a_r_e*4 a(large_windows(i))-l_2_a_r_e*3 a(large_windows(i))-l_2_a_r_e*2 a(large_windows(i))-l_2_a_r_e*1 a(large_windows(i))-l_2_a_r_e*0 a(large_windows(i))+l_2_a_r_e]; 
end 

C= cell2mat(B'); 

Je lis aussi une question avant de poster, mais This was to specific

B ne figure pas dans A cette question est donc pas utile Find complement of a data frame (anti - join)

I don't know how to useismember dans thi s cas particulier

J'espère que mon dessin pourrait mieux expliquer mon problème :)

Merci pour votre temps enter image description here

+0

Je ne sais pas si je comprends bien ce que vous cherchez. Par exemple, à la place de votre boucle for, vous pouvez utiliser 'large_windows = repmat (large_indexes. ', Window_size, 1) + (0: 3).'' Ou 'large_windows = bsxfun (@ plus, large_indexes, 0: 3). ' 'pour créer votre tableau' large_windows'. Ce serait probablement un peu plus efficace. Cherchez-vous ce genre de choses? Votre objectif est-il de rendre votre code plus rapide? Traitez-vous de grandes quantités de données? Ou essayez-vous juste de prétendre le code et de comprendre des trucs fantaisistes d'indexation matlab? – Max

+0

@uomodellamansarda Si le résultat final est la matrice B, vous n'avez pas vraiment besoin de calculer la matrice "large_windows". Vous pouvez obtenir "B" directement à partir de "large_indexes". Que pensez-vous de cela? –

+0

@Max mon objectif est de rendre mon code plus rapide, parce que j'ai plus de 4k lignes, mais je veux comprendre des trucs de matlab-indexing (ils ne sont pas utiles, je suis un noob, pas d'informatique et tout le monde me décourage à utiliser pour la boucle sur matlab) :) Merci pour votre suggestion je vais étudier et ensuite l'essayer :) <3 –

Répondre

1

Voici une nouvelle approche pour obtenir le résultat que vous vouliez réellement atteindre. J'ai corrigé 2 erreurs que vous avez faites et remplacé toutes les boucles for avec bsxfun ce qui est une fonction très efficace pour faire des choses comme ça. Pour Matlab R2016b ou plus récent, vous pouvez également implicit expansion au lieu de bsxfun.
Mon commence à vous l'implémentation de la fenêtre coulissante. Au lieu de votre for -loop, vous pouvez utiliser

stdInds=bsxfun(@plus,1:step:(size(a,1)-overlap),(0:3).'); 
std_vals=std(a(sub2ind(size(a),stdInds,repmat(5,size(stdInds))))); 

ici. Le bsxfun crée un tableau qui contient les lignes de vos fenêtres. Il contient 1 windo dans chaque colonne. Ces lignes doivent être transformées en index linéaire du tableau a afin d'obtenir un tableau de valeurs pouvant être transmises à la fonction std.Dans votre implémentation, vous avez fait une petite erreur ici, parce que votre for -loop se termine à size(a,1)-window_size et devrait en fait se terminer à size(a,1)-overlap, parce que sinon il vous manque la dernière fenêtre.
Maintenant que nous avons obtenu les valeurs std-des fenêtres nous pouvons vérifier ceux qui sont supérieurs à votre seuil prédéfini, puis les Reprenez dans les lignes correspondantes:

highStdWindows=find(std_vals_2>threshold); 
highStdRows=bsxfun(@plus,highStdWindows*step-step+1,(0:3).'); 

highStdWindows contient les index des fenêtres, que avoir des valeurs Std élevées. Dans la ligne suivante, nous calculons les lignes de départ de ces fenêtres en utilisant highStdWindows*step-step+1 puis nous calculons les autres lignes qui correspondent à chaque fenêtre en utilisant à nouveau le bsxfun.
Maintenant, nous arrivons à l'erreur réelle dans votre code. Cette ligne ici

B{i}=[a(large_windows(i))-l_2_a_r_e*4 a(large_windows(i))-l_2_a_r_e*3 a(large_windows(i))-l_2_a_r_e*2 a(large_windows(i))-l_2_a_r_e*1 a(large_windows(i))-l_2_a_r_e*0 a(large_windows(i))+l_2_a_r_e]; 

ne fait pas ce que vous vouliez faire. Malheureusement, vous avez perdu quelques parenthèses ici. De cette façon, vous prenez l'élément grand_windows (i) de la matrice a et en soustrayez 4*l_2_a_r_e. Qu'est-ce que vous vouliez écrire était

B{i}==[a(large_windows(i)-l_2_a_r_e*4) % and so on 

De cette façon, vous soustrayez le 4*l_2_a_r_e de l'indice que vous passez à a. Cela serait encore faux, car dans large_windows vous avez enregistré des numéros de ligne et non des index linéaires correspondant à la matrice a.
Néanmoins cela peut être réalisé beaucoup plus facile en utilisant l'indexation indicée au lieu d'indexation linéaire:

rowList=reshape(highStdRows,1,[]); 
C=a(rowList,:); % all columns (:) and from the rows in rowList 

Ces deux lignes faciles dire Matlab de prendre toutes les lignes qui sont stockées dans highStdRows avec toutes les colonnes (exprimées par le :). Avec ceci s'il y a deux fenêtres adjacentes avec des valeurs Std élevées, vous obtiendrez les lignes qui se chevauchent deux fois. Si vous ne voulez pas, vous pouvez utiliser ce code à la place:

rowList=unique(reshape(highStdRows,1,[])); 
C=a(rowList,:); 

Si vous souhaitez obtenir d'autres sur la façon dont l'indexation intérieur Matlab fonctionne jeter un oeil à post de LuisMendo sur ce sujet.

+0

merci j'ai compris toutes mes erreurs! Maintenant, j'essaie de comprendre ceci: 'highStdWindows * step-step + 1' Est clair comment' bsxfun' fonctionne, n'est pas clair pourquoi vous devriez multiplier pour '* step', puis soustraire' -step + 1' :) J'ai essayé le code sur matlab, pour voir le résultat, mais je suis coincé sur ce point. Merci d'avance –

+0

Dans 'highStdWindows' nous stockons les numéros des fenêtres qui ont des valeurs Std élevées. Alors maintenant, nous devons calculer les numéros de ligne correspondants. Imaginez que nous ayons juste pour les fenêtres de la taille 4 et avec le chevauchement un et la première, la troisième et la quatrième fenêtre ont des valeurs Std élevées. Maintenant 'highStdWindows' contiendrait le tableau' [1, 3, 4] ', mais nous devons calculer les lignes, que ces fenêtres commencent par. Multiplier ce vecteur avec 'step' et ajouter' -step + 1' fait exactement cela. par exemple. La fenêtre 3 se compose de '[7 8 9 10]' et nous calculons la ligne de départ avec '3 * étape-étape + 1 = 7' et les autres avec' bsxfun' – Max

+0

J'espère que c'est plus clair maintenant – Max