2013-10-03 11 views
5

我有以下性能問題關於大的文本文件輸入(〜500K線)和後續的數據分析刪除從文本文件reoccuring行與增強的性能

考慮具有與所述特徵模擬下面的示例性的結構,即兩個頭線可以在文本文件中某處再現文本文件data.txt

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 

我寫和其工作的代碼如下:

%# 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 

我選擇了在一切看在奧得河的字符串能夠去除在DATA到處刪除標題行。

停止時間告訴我,代碼中最慢的部分是轉換[A] = cellfun(@str2double,DATA{i})雖然str2double已經是比較str2num更快的選擇。第二個最慢的部分是textscan

現在的問題是,有沒有更快的方法來處理這個問題?

請讓我知道如果我應該進一步明確。如果有一個我從未見過的非常明顯的解決方案,請原諒我,現在我只用Matlab工作了三個星期。

回答

4

您可以使用名爲CommentStyletextscan一個選項,將跳過你的文件(重複2個headerlines你的情況)的一部分,並閱讀一個函數調用您的文件。

作爲doc saysCommentStyle可以以2種方式使用:一個字符串如'%'忽略字符在同一行上,或兩個字符串的單元陣列後面的字符串,如{'/*', '*/'},忽略字符之間兩個字符串(包括行尾)。我們將在這裏使用第二個選項:刪除Name-之間的字符。由於結尾字符串由重複的-字符組成,因此我們需要指定整個字符串。

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

您可以使用datenum將日期字符串轉換爲有意義的數字。

DATA_date = datenum(C{2}) 
+0

這適用於我的數據。避免使用字符串進行雙倍轉換會使時間縮短約60%! – Lukas

2

雖然從長遠來看,如果可以修復數據採集以避免這種情況會更好,但您可以在文本掃描中利用HeaderLines

如果可能的話(即通過估計大小上限和修剪零),此示例代碼將工作但預分配c3/c4。基本上,在第一次呼叫textscan時,它將跳過前兩行,並繼續,直到遇到與格式不兼容的行(例如通過重複標題的中途),或者直到到達文件的結尾。不過,它記得它的位置。

下次調用textscan時,它跳過該行的剩餘部分和下一行,然後繼續(直到eof或另一組標題行等)。如果您已達到文件末尾,textscan將無誤地運行,但length(data{3})應該爲零。

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

我很喜歡這種方法。我比較@Magla的答案,這不需要兩個(或通常N)標題行中的特定內容。對於我的代碼,Magla的解決方案實施時間更短,因此我選擇它作爲最佳答案。另外,使用'commentstyle'的速度比使用速度快50%。 – Lukas