2013-10-03 17 views
5

Ho il seguente problema di prestazioni relativo all'ingresso di file di testo di grandi dimensioni (linee ~ 500k) e dati successivi che analizzano.Rimuovere le righe ricorrenti dal file di testo con prestazioni migliorate

consideri un file di testo data.txt avente la seguente struttura di esemplare con la peculiarità che i due righe di intestazione può riapparire da qualche parte nel file di testo:

Name Date Val1 val2 
--- ------- ---- ---- 
BA 2013-09-07 123.123 1232.22 
BA 2013-09-08 435.65756 2314.34 
BA 2013-09-09 234.2342 21342.342 

Il codice che ho scritto e che sta lavorando è la seguente :

%# Read in file using textscan, read all values as string 

inFile = fopen('data.txt','r'); 
DATA = textscan(inFile, '%s %s %s %s'); 
fclose(inFile); 

%# Remove the header lines everywhere in DATA: 
%# Search indices of the first entry in first cell, i.e. 'Name', and remove 
%# all lines corresponding to those indices 

[iHeader,~] = find(strcmp(DATA{1},DATA{1}(1))); 
for i=1:length(DATA) 
    DATA{i}(iHeader)=[]; 
end 

%# Repeat again, the first entry corresponds now to '---' 

[iHeader,~] = find(strcmp(DATA{1},DATA{1}(1))); 
for i=1:length(DATA) 
    DATA{i}(iHeader)=[]; 
end 

%# Now convert the cells for column Val1 and Val2 in data.txt to doubles 
%# since they have been read in as strings: 

for i=3:4 
    [A] = cellfun(@str2double,DATA{i}); 
    DATA{i} = A; 
end 

ho scelto di leggere in ogni cosa come una stringa in oder di essere in grado di rimuovere il rimuovere le righe di intestazione ovunque in DATA.

Arrestare l'ora mi dice che la parte più lenta del codice è la conversione [A] = cellfun(@str2double,DATA{i}) sebbene sia già la scelta più veloce rispetto a str2num. La seconda parte più lenta è textscan.

La domanda è ora, c'è un modo più veloce per affrontare questo problema?

Per favore fatemi sapere se dovrei ulteriormente chiarire. E perdonami se c'è una soluzione molto ovvia che non ho visto, sto solo lavorando con Matlab da tre settimane.

risposta

4

È possibile utilizzare l'opzione di textscan chiamato CommentStyle che saltare una parte del file (i ripetuti 2 headerlines nel tuo caso), e leggere il file in una chiamata di funzione.

Come doc says, CommentStyle può essere utilizzato in 2 modi: una singola stringa come '%' ignorare caratteri che seguono la stringa sulla stessa linea, o una matrice di celle di due stringhe, come {'/*', '*/'}, ignorare caratteri tra la due stringhe (compresa la fine delle linee). Utilizzeremo la seconda opzione qui: rimuovere i caratteri tra Name e -. Poiché la stringa finale è costituita da un carattere ripetuto -, è necessario specificare l'intera stringa.

inFile = fopen('data.txt','r'); 
DATA = textscan(inFile, '%s %s %f %f', ... 
     'Commentstyle', {'Name';'--- ------- ---- ----'}); 
fclose(inFile); 

È possibile convertire una stringa data in un numero significativo utilizzando datenum.

DATA_date = datenum(C{2}) 
+0

Questo ha funzionato bene per i miei dati. Evitare l'uso della stringa per raddoppiare la conversione diminuisce il tempo di 60%! – Lukas

2

Anche se a lungo termine sarebbe meglio, se possibile, correggere l'acquisizione dei dati per evitare ciò, è possibile utilizzare HeaderLines in textscan.

Questo codice di esempio funziona ma prealloca c3/c4 se possibile (vale a dire stimando il limite superiore della dimensione e tagliando gli zeri in seguito). Fondamentalmente, alla prima chiamata textscan salterà le prime due righe e continuerà fino a quando non colpisce una riga incompatibile con il formato (ad esempio a metà dell'intestazione ripetuta), o finché non raggiunge la fine del file. Si ricorda la posizione in cui è arrivato, però.

La volta successiva che viene chiamato textscan, salta il resto di quella riga e la riga successiva successiva, quindi continua (fino a eof o un altro insieme di righe di intestazione, ecc.). Se hai raggiunto la fine del file, textscan verrà eseguito senza errori, ma length(data{3}) dovrebbe essere zero.

c3 = []; 
c4 = []; 
fid = fopen('data.txt'); 
data = textscan(fid,'%s %s %f %f','HeaderLines',2); 
l = length(data{3}); 
while l>0 %stop when we hit eof 
    c3 = [c3; data{3}]; 
    c4 = [c4; data{4}]; 
    data = textscan(fid,'%s %s %f %f','HeaderLines',2); 
    l = length(data{3}); 
end 
+0

Mi piace molto questo approccio. Confronto con la risposta di @Magla questo non richiede la specifica delle due (o gernerally N) linee di intestazione. Per il mio codice la soluzione di Magla è stata più breve da implementare, quindi l'ho scelta come risposta più appropriata. Inoltre, in termini di velocità usando 'commentstyle' è il 50% più veloce. – Lukas