Примечание:
Существует немало улучшений, которые вы можете сделать для скорости, но есть и исправления. Вы предварительно выделяете конечную выходную переменную с жестко закодированными значениями:
pan_mat_2 = zeros(2359,4126);
Но позже вы заполняете ее в цикле, который запускает for i = 1:length
.
length
- полное количество выбранных строкиз файла. В вашем примере файла есть только 784
строк. Таким образом, даже если бы все ваши строки были действительны (нормально для анализа), вы бы заполняли только первые 784
строк из всех 2359
строк, которые вы выделили в своем pan_mat_2
. На практике этот файл содержит только 400 допустимых строк данных, поэтому ваш pan_mat_2
может быть определенно меньше.
Я знаю, что вы не могли знать, что перед анализом их было проанализировано только 400 строк, но вы знали изначало, что у вас была только 784
строка для разбора (у вас была информация в переменной length
). Таким образом, в случае, подобном этому, предварительно выделите 784
и только позже отбросьте пустые строки.
К счастью, предлагаемое мной решение не требует предварительного выделения большего, чем сброс. Матрицы будут иметь правильный размер с самого начала.
Код:
%%
file_pan = 'Pandora107s1_BostonMA_20190814_L0.txt' ;
delimiterIn = '\t';
headerlinesIn = 41;
A = readtable(file_pan,'HeaderLines', 41, 'Delimiter', '\t'); %Reading the file as a table
A = table2cell(A); % Converting file to a cell
A = regexp(A, ' ', 'split'); % converting cell to a structure matrix.
%% Remove lines which won't be parsed
% Count the number of elements in each line
nelem = cell2mat( cellfun( @size , A ,'UniformOutput',0) ) ;
nelem(:,1) = [] ;
% find which lines does not have enough elements to be parsed
idxLine2Remove = ~(nelem > 4120 & nelem < 4140) ;
% remove them from the data set
A(idxLine2Remove) = [] ;
%% Remove nesting in cell array
nLinesToParse = size(A,1) ;
A = reshape( [A{:}] , [], nLinesToParse ).' ;
% now you have a cell array of size [400x4126] cells
%% Now separate the columns with different data type
% Column 1 => [String] identifier
% Column 2 => Timestamp
% Column 3 to 4125 => Numeric values
% Column 4126 => empty cell created during the 'split' operation above
% because of a trailing space character.
LineIDs = A(:,1) ;
TimeStamps = A(:,2) ;
Data = A(:,3:end-1) ; % fetch to "end-1" to discard last empty column
%% now extract the values
% You could do that directly:
% pan_mat = str2double(Data) ;
% but this takes a long time. A much computationnaly faster way (even if it
% uses more complex code) would be:
dat = strjoin(Data) ; % create a single long string made of all the strings in all the cells
nums = textscan( dat , '%f' , Inf ) ; % call textscan on it (way faster than str2double() )
pan_mat = reshape( cell2mat( nums ) , nLinesToParse ,[] ) ; % reshape to original dimensions
%% timestamps
% convert to character array
strTimeStamps = char(TimeStamps) ;
% convert to matlab own datetime numbering. This will be a lot faster if
% you have operations to do on the time stamps later
ts = datenum(strTimeStamps,'yyyymmddTHHMMSSZ') ;
%% If you really want them the way you had it in your example
strTimeStamps(:,9) = ' ' ; % replace 'T' with ' '
strTimeStamps(:,end) = ' ' ; % replace 'Z' characters with ' '
%then same again, merge into a long string, parse then reshape accordingly
strdate = reshape(strTimeStamps.',1,[]) ;
tmp = textscan( strdate , '%d' , Inf ) ;
datetime_mat = reshape( double(cell2mat(tmp)),2,[]).' ;
Производительность:
Как вы видите на моем компьютере, ваш исходный код выполняется ~ 102 секунды, причем 80% этого (81 с) затрачивается на вызовфункция str2double()
3,302,400 раз!
Мое решение, работающее с тем же входным файлом, занимает ~ 5,5 секунд, причем половина времени уходит на вызов strjoin()
3 раза.
КогдаВы читаете приведенный выше код, пытаетесь понять, как я ограничил повторение вызова функции в длинных циклах, пытаясь сделать все как можно более векторизованным.