Eliminare righe da matrice

di il
11 risposte

Eliminare righe da matrice

Buongiorno a tutti, vi spiego il mio problema.
Ho una matrice composta da 7 colonne e m righe.
Voglio eliminare le righe nelle quali il valore in prima colonna non sia compreso tra due valori.
Ho provato a fare un caso più semplice, solo con una disuguaglianza, ma non ci riesco. credo che il problema sia legato al fatto che la matrice cambia dimensione.. dico questo perchè ho provato con una matrice banale 4X4 ed avevo problemi.

il mio ultimo tentativo è questo:

[m,n]=size(Matrix);

for k=1:m
if Matrix(k,3)<0
Matrix(k,:)=[];
end
end

potete aiutarmi?

11 Risposte

  • Re: Eliminare righe da matrice

    L'ipotesi fatta sulla ragione per la quale lo script non dà il risultato atteso è corretta.
    Modificando il numero di righe della matrice all'interno del loop rende non più coerente l'indicizzazione.

    Una possibile soluzione consiste nel dividere il problema in due parti:
    [1] individuazione dell'indice delle righe da eliminare
    [2] eliminazione delle righe

    Per individuare l'indice delle righe da eliminare si può procedere nel modo seguente:
    [1] estrarre in un vettore la prima colonna (questo passo non è strettamente necessario, ma semplifica la notazione del codice)
    [2] utilizzare la funzione built-in "find" per trovare gli indici degli elementi del vettore che verificano la condizione
    [3] utilizzare gli indici ricavati al passo precedente per cancellare le righe

    La complessità della porzione di codice che, tramite la funzione "find" individua gli indici varia in funzione del tipo di condizione:
    [1] il caso più semplice è costituito dal caso in cui la condizione sia: eliminare le righe il valore della prima colonna delle quali sia maggiore (minore) di una soglia
    [2] il caso intermedio è rappresentato dal caso nel quale la condizione sia: eliminare le righe il valore della prima colonna delle quali sia compreso all'interno di un intervallo
    [2] il caso più complicato (relativamente complicato) è rappresentato dal caso nel quale la condizione sia: eliminare le righe il valore della prima colonna delle quali sia esterno ad un intervallo

    Caso 1: cancellazione righe con valore prima colonna INFERIORE SOGLIA

    idx=find(prima_colonna < soglia);
    m(idx)=[];

    gli indici individuati dalla funzione "find" (prima_colonna è il vettore che contiene la prima colonna della matrice) corrispondono agli indici delle righe da eliminare.

    Caso 2: Cancellazione righe con valore prima colonna COMPRESO NELL'INTERVALLO

    idx_inf=find(prima_colonna > soglia_sup);
    idx_sup=find(prima_colonna < soglia_inf);
    idx=sort([idx_inf;idx_sup]);
    m1=m(idx,:);

    si può invocare due volte la funzione "find" per trovare gli indici corrispondenti ai valori, rispettivamente, inferiori e superiori agli estremi dell'intervallo (soglia_inf;soglia_sup).
    Gli indici vengono quindi uniti a creare la lista complessiva degli indici delle righe ella matrice risultante dopo la cancellazione

    Caso 3: Cancellazione righe con valore prima colonna ESTERNO ALL'INTERVALLO

    idx_inf=find(prima_colonna > soglia_inf);
    idx_sup=find(prima_colonna < soglia_sup);
    a1=zeros(1,length(prima_colonna));
    a2=a1;
    a1(idx_inf)=idx_inf;
    a2(idx_sup)=idx_sup;
    idx=find((a1.*a2) > 0);
    m1=m(idx,:);

    La prima chiamata alla funzione "find" individua gli indici delle righe con valore della prima colonna superiore alla soglia inferiore.
    La seconda chiamata alla funzione "find" individua gli indici delle righe con valore della prima colonna inferiore alla soglia superiore.

    Gli indici delle righe da eliminare saranno quelli non comuni alle due chiamate.
    Per individuarli si possono costruire due vettori di "0" ("a1" e "a2") ai quali vengono, successivamente assegnati i valori degli indici trovati dalla funzione "find" nelle corrispondenti locazioni.
    Il prodotto elemento per elemento dei due vettori darà un risultato diverso da 0 nel caso l'indice compaia in entrambi i vettori; questo, individuato tramite un'altra chiamata alla funzione "find" sarà l'indice della riga da conservare.

    Il tutto, ovviamente, si può realizzare anche tramite "cicli for", ma per matrici di grandi dimensioni, i tempi di esecuzione risultano molto più lunghi.

    La soluzione proposta è stata implementata nello script che segue.
    
    % 
    % Definizione matrice di esempio
    % 
    m=magic(9);
    m=m(randperm(9),:);
    % 
    % Definizione matrice di valori "NaN" (solo per debug). Alle matrice "m1"
    % verranno sovrascritte le righe che NON dovranno essere eliminate di
    % conseguenza le righe con valori NaN corrisponderanno alle righe da
    % eliminare
    % 
    m1=NaN(size(m));
    % 
    % Estrazione dei valori della prima colonna della matrice di input
    % 
    prima_colonna=m(:,1)
    % 
    % Cancellazione righe con valore prima colonna ESTERNO ALL'INTERVALLO
    % (soglia_inf;soglia_sup)
    % 
    % 
    % Definizione dei valori di soglia
    % 
    soglia_inf=28;
    soglia_sup=64;
    idx_inf=find(prima_colonna > soglia_inf);
    idx_sup=find(prima_colonna < soglia_sup);
    a1=zeros(1,9);
    a2=a1;
    a1(idx_inf)=idx_inf;
    a2(idx_sup)=idx_sup;
    idx=find((a1.*a2) > 0);
    m
    m2=m(idx,:)
    m1(idx,:)=m(idx,:)
    [soglia_inf soglia_sup]
    % 
    % Cancellazione righe con valore prima colonna COMPRESO NELL'INTERVALLO
    % (soglia_inf;soglia_sup)
    % 
    % 
    % Definizione dei valori di soglia
    % 
    soglia_inf=28;
    soglia_sup=64;
    m1=NaN(size(m));
    idx_inf=find(prima_colonna > soglia_sup);
    idx_sup=find(prima_colonna < soglia_inf);
    idx=sort([idx_inf;idx_sup]);
    m
    m2=m(idx,:)
    m1(idx,:)=m(idx,:)
    [soglia_inf soglia_sup]
    % 
    % Cancellazione righe con valore prima colonna SUPERIORE SOGLIA
    % 
    % 
    % Definizione dei valori di soglia
    % 
    soglia=33;
    m1=NaN(size(m));
    idx=find(prima_colonna < soglia);
    m
    m2=m(idx,:)
    m1(idx,:)=m(idx,:)
    [soglia]
    % 
    % Cancellazione righe con valore prima colonna INFERIORE SOGLIA
    % 
    % 
    % Definizione dei valori di soglia
    % 
    soglia=42;
    m1=NaN(size(m));
    idx=find(prima_colonna > soglia);
    m
    m2=m(idx,:)
    m1(idx,:)=m(idx,:)
    [soglia]
    
    Hope this helps.
  • Re: Eliminare righe da matrice

    Gentilissimo.. dimmi che ne pensi della mia soluzione.
    La matrice è costituita da vettori presi in un file di testo.
    Quindi ho prima letto i valori dal file:

    x=C{:,1}; % [mm]
    y=C{:,2}; % [mm]
    z=C{:,3}; % [mm]

    poi usato il comando find:

    a=find(680<x & x<720);

    e poi:

    Matrix=[x(a), y(a), z(a)];
  • Re: Eliminare righe da matrice

    Mi sembra una soluzione semplice ed elegante e, soprattutto, ... funziona!

    Si potrebbe aggiungere un controllo sull'output della funzione "find": cosa fare se ritorna un vettore vuoto, se cioè nessun elemento della prima colonna (vettore "x") verifica la condizione?

    Per curiosità, hai usato la funzione "textscan" per leggere il file ("textscan" ritorna un cellarray)?
    Se il file di input non ha righe di testo ecc., si può usare la funzione "load" che restituisce una matrice con il nome uguale a quello del file.
    In questo caso si può fare tutto con solo due istruzioni (assumendo che il file di input si chiami "input_file.txt"):

    load 'input_file.txt'
    M=input_file(find(680<input_file(:,1) & input_file(:,1)<720),:);
  • Re: Eliminare righe da matrice

    Grazie mille, gentilissimo.
    Si ho usato la funzione textscan.
    Grazie per il consiglio però prima di selezionare solo le righe che vengono dal comando find, devo calcolare il modulo di queste componenti e quindi prendere solo quelle con valore compreso tra le due soglie, quindi credo vada bene così
  • Re: Eliminare righe da matrice

    Ciao, sto provando a eseguire il tuo codice per il caso " intervallo compreso".
    Ma non funziona... Non mi restituisce i valori compresi.Questo è il codice:
    [data, CVA, CIMA]=textread('C:\\Matrice1.txt','%s %f %f');
    m=[CVA,CIMA]
    m1=NaN(size(m));
    % Estrazione dei valori della prima colonna della matrice di input
    seconda_colonna=m(:,2)
    %Cancellazione righe con valore prima colonna COMPRESO NELL'INTERVALLO
    % (soglia_inf;soglia_sup)
    % Definizione dei valori di soglia
    soglia_inf=0.029;
    soglia_sup=0.068;
    m1=NaN(size(m));
    idx_inf=find(seconda_colonna > soglia_sup);
    idx_sup=find(seconda_colonna < soglia_inf);
    idx=sort([idx_inf;idx_sup]);
    m
    m2=m(idx,:)
    m1(idx,:)=m(idx,:)
    [soglia_inf soglia_sup]
  • Re: Eliminare righe da matrice

    La cosa più semplice che puoi fare è:
    [*] identificare gli indici delle righe che contengono i valori inferiori alla soglia inferiore (verifica se considerare o meno quelli eventualmente uguali alla soglia)
    [*] identificare gli indici delle righe che contengono i valori superiori alla soglia inferiore (verifica se considerare o meno quelli eventualmente uguali alla soglia)

    A questo punto puoi estrarre direttamente due matrici: quella con i valori esterni all'intervallo e quella con i valori interni all'intervallo.

    Nell'esempio che segue il processo è applicato ad una semplice matrice (13 x 2) di interi per poter verificare il risultato.
    Le istruzioni
    
    idx_sup=m(:,1) >= soglia_sup
    idx_inf=m(:,1) <= soglia_inf
    
    identificano gli indici in formato "logical".
    Puoi usare questi indici logici per accedere agli elementi della matrice: MatLab considererà solo le righe che corrispondono ai valori "1"

    Le due matrici "m1" e "m2" vengono create combinando gli indici logici:
    
    idx_inf | idx_sup
    
    identifica gli elementi con valori esterni all'intervallo
    
    ~idx_inf & ~idx_sup
    
    identifica gli elementi con valori interni all'intervallo

    
    % Define the input matrix
    m=[
       102    80
        89    10
        81    65
        81    41
        93    50
        57    86
       121   101
        80   118
         4     1
        73   122
         5    29
        51    87
        59    15
    ]
    % Define the thresholds
    soglia_inf=33
    soglia_sup=99
    % Get the indices
    idx_sup=m(:,1) >= soglia_sup
    idx_inf=m(:,1) <= soglia_inf
    %  Extract the data
    m1=m(idx_inf | idx_sup,:)
    m2=m((~idx_inf & ~idx_sup),:)
    
    Data la matrice "m"
    
    m=[
       102    80
        89    10
        81    65
        81    41
        93    50
        57    86
       121   101
        80   118
         4     1
        73   122
         5    29
        51    87
        59    15
    ]
    
    si ottengono le due matrici:
    
    m1 =
    
        89    10
       121   101
        80   118
         4     1
        73   122
         5    29
        59    15
    
    m2 =
    
       102    80
        81    65
        81    41
        93    50
        57    86
        51    87
    
  • Re: Eliminare righe da matrice

    Tutto molto chiaro ora. Sono riuscita ad implementare il codice. Grazie mille! Ma ho un altra domanda..se volessi porre la condizione a tutte e due le colonne della matrice? e poi sempre avere un'unica matrice?
  • Re: Eliminare righe da matrice

    Se vuoi estendere contemporaneamente la verifica della condizione a tutte e due le colonne, non devi fare altro che replicare l'istruzione per il controllo ed unire le due parti con un "&" (and).
    
    % Define the input matrix
    m=[
       102    80
        89    10
        81    65
        81    41
        93    50
        57    86
       121   101
        80   118
         4     1
        73   122
         5    29
        51    87
        59    15
    ]
        
    % Define the thresholds
    soglia_inf=33
    soglia_sup=99
    % Get the indices for the first column
    idx_sup_1=m(:,1) >= soglia_sup
    idx_inf_1=m(:,1) <= soglia_inf
    % Get the indices for the second column
    idx_sup_2=m(:,2) >= soglia_sup
    idx_inf_2=m(:,2) <= soglia_inf
    %  Extract the data
    m1=m((idx_inf_1 | idx_sup_1) & (idx_inf_2 | idx_sup_2),:)
    m2=m((~idx_inf_1 & ~idx_sup_1) & (~idx_inf_2 & ~idx_sup_2),:)
    
    Partendo dalla matrice:
    
    m=[
       102    80
        89    10
        81    65
        81    41
        93    50
        57    86
       121   101
        80   118
         4     1
        73   122
         5    29
        51    87
        59    15
    ]
    
    ottieni:
    
    m1 =
    
       121   101
         4     1
         5    29
    
    m2 =
    
       81   65
       81   41
       93   50
       57   86
       51   87
    
  • Re: Eliminare righe da matrice

    Mi sfugge un passaggio nell'estrazione degli indici:
    
    idx_sup=m(:,1) >= soglia_sup;
    idx_inf=m(:,1) < soglia_inf
    
    Queste due righe se dovessimo spiegarle a parole, significano: prendi tutti gli indici delle righe della matrice dove i valori della colonna 1 sono maggiori o uguali al valore soglia superiore e prendi tutti gli indici delle righe della matrice dove i valori della colonna 1 sono minori o uguali al valore soglia inferiore?
  • Re: Eliminare righe da matrice

    E' quasi così.
    L'istruzione
    
    idx_sup=m(:,1) >= soglia_sup
    
    è l'equivalente di
    
    for i=1:size(m,1)
       if(m(i,1) >= soglia_sup)
          idx_sup(i)=logical(1)
       else
          idx_sup(i)=logical(0)
       end   
    end
    
    l'istruzione "logical(1) converte il valore "1" dal tipo "double" al tipo "logical".
    "idx_sup" non è quindi un vettore di indici della matrice "m", ma un vettore di valori di tipo "logical" che assumono il valore "1" quando la condizione "m(i,1) >= soglia_sup" è verificata, "0" in caso contrario.
    I valori di tipo "logical" possono essere usati per accedere a vettori e matrici.
    Nello specifico, quando usi il vettore "idx_sup" per accedere alle righe della matrice "m", ad esempio:
    
    x=m(idx_sup,1)
    
    l'istruzione viene implicitamente espansa in
    
    cnt=0
    for i=1:length(idx_sup)
       if(idx_sup(i) == 1)
          cnt=cnt+1
          xxx(cnt)=m(i,1)
       end
    end
    
    L'istruzione
    
    x=m(idx_sup,1)
    
    "funziona" grazie al fatto che il vettore "idx_sup" è di tipo "logical".
    Se invece scrivessi scritto
    
    
    for i=1:size(m,1)
       if(m(i,1) >= soglia_sup)
          idx_sup(i)=1
       else
          idx_sup(i)=0
       end   
    end
    due cicli apparentemente simili, il vettore idx_sup risulterebbe di tipo "double" e non potresti usarlo per estrarre i valori dalla matrice "m"; in questo caso, infatti:
    
    m(idx_sup,1)
    
    ritornerebbe un messaggio di errore:

    error: m(0,_): subscripts must be either integers 1 to (2^63)-1 or logicals
  • Re: Eliminare righe da matrice

    Gentilissimo, ho capito. Grazie mille della spiegazione.
Devi accedere o registrarti per scrivere nel forum
11 risposte