2015-12-29 17 views
5

Ho dati simili:Come si calcola la lunghezza delle occorrenze continue di un valore (tempi di funzionamento) in una matrice?

1  0  1 
1  1  1 
0  1  1 
1  1  1 
1  1  1 
1  1  1 
1  1  0 
1  1  1 
1  1  1 
1  1  1 
1  1  1 
1  1  1 
1  1  1 
1  1  1 
0  0  1 
1  1  1 
1  1  1 
1  1  1 

Ciascuna colonna rappresenta un dispositivo, e ogni riga rappresenta un periodo di tempo. Ogni punto dati indica se il dispositivo era attivo o meno in quel periodo di tempo. Sto provando a calcolare la lunghezza di ogni tempo di attività, o "incantesimo", che ogni dispositivo era attivo. In altre parole, la lunghezza di ogni incantesimo di quelli continui in ogni colonna. In questo caso, sarebbe 2 11 3 per la prima colonna e così via.

Questo è facile da fare con un dispositivo (una singola colonna di dati):

rng(1) 

%% Parameters 
lambda = 0.05;  % Pr(failure) 
N = 1;    % number of devices 
T = 18;    % number of time periods in sample 

%% Generate example data 
device_status = [rand(T, N) >= lambda ; false(1, N)]; 

%% Calculate spell lengths, i.e. duration of uptime for each device 
cumul_status = cumsum(device_status); 

% The 'cumul_status > 0' condition excludes the case where the vector begins with one 
% or more zeros 
cumul_uptimes = cumul_status(device_status == 0 & cumul_status > 0); 
uptimes = cumul_uptimes - [0 ; cumul_uptimes(1:end-1)]; 

così potrebbe semplicemente scorrere sulle colonne e fare questo una colonna alla volta e utilizzando parfor (per esempio) per eseguire questo in parallelo. C'è un modo per farlo su tutte le colonne contemporaneamente, usando operazioni con matrici vettorializzate?

EDIT: Devo aggiungere che questo è complicato dal fatto che ogni dispositivo può avere un numero diverso di periodi di tempo.

+0

Puoi provare ad usare qualcosa come: 'rimodella (max (cumsum (cumprod (hankel ([zeri (1, dimensione (A, 2)); A]) '))), dimensione (A, 1) + 1, dimensione (A, 2)); 'Dove A è la matrice. Quindi puoi trovare i massimi locali, ma a volte è meglio e più veloce usare un ciclo. – obchardon

+1

Se non si dispone di molti dispositivi, penso che l'utilizzo di questo approccio con un ciclo sia perfetto. Non complicare eccessivamente le cose. Donald Knuth lo ha definito il migliore "* L'ottimizzazione prematura è la radice di tutto il male *". A meno che non si possa vedere chiaramente un'enorme differenza di runtime tra il loop su ciascun dispositivo individualmente rispetto a provare a farlo per tutti i dispositivi in ​​modo vettorializzato, non vale la pena. – rayryeng

+1

Anche come sidenote, potresti non ottenere la stessa quantità di tempo di attività per ogni colonna.Nello specifico nel tuo esempio, la prima colonna ha tre istanze di uptime mentre le ultime due ne hanno due. Questa "disuguaglianza" ostacola già la tua capacità di vettorizzazione. – rayryeng

risposta

3

Ecco un modo. Non è sicuro che contenga come vettori, però.

Lascia che la matrice di dati sia identificata come x. Quindi

[ii, jj] = find([true(1,size(x,2)); ~x; true(1,size(x,2))]); 
result = accumarray(jj, ii, [], @(x){nonzeros(diff(x)-1)}); 

produce un array di celle, in cui ogni cella corrisponde a una colonna. Nel tuo esempio,

result{1} = 
    2 
    11 
    3 
result{2} = 
    13 
    3 
result{3} = 
    6 
    11 

come funziona

L'idea è di trovare gli indici di riga e di colonna di zeri in x (vale a dire, true valori in ~x), e quindi utilizzare gli indici delle colonne come variabili di raggruppamento (primo argomento su accumarray).

All'interno di ciascun gruppo viene utilizzato lo anonymous function@(x){nonzeros(diff(x)-1)} per calcolare le differenze nelle posizioni di riga degli zeri. Possiamo applicare diff direttamente perché gli indici delle colonne da find sono già ordinati, grazie all'ordine column major di Matlab. Sottraiamo 1 perché gli zeri in x non vengono conteggiati come parte del tempo di attività; rimuovere le lunghezze di operatività pari a 0 (con nonzeros) e comprimere il vettore risultante in una cella ({...}).

Una riga di valori true viene aggiunta e anteposta a ~x per assicurarsi che vengano rilevati i periodi di uptime iniziale e finale.