Matlab: Как читать числа с запятой в качестве десятичного разделителя? - PullRequest
4 голосов
/ 20 ноября 2011

У меня есть целый ряд (сотни тысяч) довольно больших (> 0,5 МБ) файлов, где данные являются числовыми, но с запятой в качестве десятичного разделителя.Для меня нецелесообразно использовать внешний инструмент, такой как sed "s/,/./g".Когда разделитель является точкой, я просто использую textscan(fid, '%f%f%f'), но не вижу возможности изменить десятичный разделитель.Как я могу эффективно прочитать такой файл?

Пример строки из файла:

5,040000    18,040000   -0,030000

Примечание. * * * * * * * * * *Я использую Matlab.

Ответы [ 4 ]

4 голосов
/ 13 декабря 2011

С тестовым сценарием я нашел коэффициент менее 1,5.Мой код будет выглядеть так:

tmco = {'NumHeaderLines', 1      , ...
        'NumColumns'    , 5      , ...
        'ConvString'    , '%f'   , ...
        'InfoLevel'     , 0      , ...
        'ReadMode'      , 'block', ...
        'ReplaceChar'   , {',.'} } ;

A = txt2mat(filename, tmco{:});

Обратите внимание на различное значение 'ReplaceChar' и 'Блок' ReadMode '.

Я получаю следующие результаты для файла ~ 5 МБ на моемслишком новый) машина:

  • txt2mat test comma avg.время: 0,63231
  • txt2mat контрольная точка, ср.время: 0,45715
  • тестовая точкавремя: 0,4787

Полный код моего тестового скрипта:

%% generate sample files

fdot = 'C:\temp\cDot.txt';
fcom = 'C:\temp\cCom.txt';

c = 5;       % # columns
r = 100000;  % # rows
test = round(1e8*rand(r,c))/1e6;
tdot = sprintf([repmat('%f ', 1,c), '\r\n'], test.'); % '
tdot = ['a header line', char([13,10]), tdot];

tcom = strrep(tdot,'.',',');

% write dot file
fid = fopen(fdot,'w');
fprintf(fid, '%s', tdot);
fclose(fid);
% write comma file
fid = fopen(fcom,'w');
fprintf(fid, '%s', tcom);
fclose(fid);

disp('-----')

%% read back sample files with txt2mat and textscan

% txt2mat-options with comma decimal sep.
tmco = {'NumHeaderLines', 1      , ...
        'NumColumns'    , 5      , ...
        'ConvString'    , '%f'   , ...
        'InfoLevel'     , 0      , ...
        'ReadMode'      , 'block', ...
        'ReplaceChar'   , {',.'} } ;

% txt2mat-options with dot decimal sep.
tmdo = {'NumHeaderLines', 1      , ...
        'NumColumns'    , 5      , ...
        'ConvString'    , '%f'   , ...
        'InfoLevel'     , 0      , ...
        'ReadMode'      , 'block'} ;

% textscan-options
tsco = {'HeaderLines'   , 1      , ...
        'CollectOutput' , true   } ;


A = txt2mat(fcom, tmco{:});
B = txt2mat(fdot, tmdo{:});

fid = fopen(fdot);
C = textscan(fid, repmat('%f',1,c) , tsco{:} );
fclose(fid);
C = C{1};

disp(['txt2mat  test comma (1=Ok): ' num2str(isequal(A,test)) ])
disp(['txt2mat  test dot   (1=Ok): ' num2str(isequal(B,test)) ])
disp(['textscan test dot   (1=Ok): ' num2str(isequal(C,test)) ])
disp('-----')

%% speed test

numTest = 20;

% A) txt2mat with comma
tic
for k = 1:numTest
    A = txt2mat(fcom, tmco{:});
    clear A
end
ttmc = toc;
disp(['txt2mat  test comma avg. time: ' num2str(ttmc/numTest) ])

% B) txt2mat with dot
tic
for k = 1:numTest
    B = txt2mat(fdot, tmdo{:});
    clear B
end
ttmd = toc;
disp(['txt2mat  test dot   avg. time: ' num2str(ttmd/numTest) ])

% C) textscan with dot
tic
for k = 1:numTest
    fid = fopen(fdot);
    C = textscan(fid, repmat('%f',1,c) , tsco{:} );
    fclose(fid);
    C = C{1};
    clear C
end
ttsc = toc;
disp(['textscan test dot   avg. time: ' num2str(ttsc/numTest) ])
disp('-----')
0 голосов
/ 08 октября 2012

Мое решение (предполагается, что запятые используются только в качестве десятичных заполнителей, а пробелы выделяют столбцы):

fid = fopen("FILENAME");
indat = fread(fid, '*char');
fclose(fid);
indat = strrep(indat, ',', '.');
[colA, colB] = strread(indat, '%f %f');

Если вам нужно удалить одну строку заголовка, как я, то это должно работать:

fid = fopen("FILENAME");                  %Open file
indat = fread(fid, '*char');              %Read in the entire file as characters
fclose(fid);                              %Close file
indat = strrep(indat, ',', '.');          %Replace commas with periods
endheader=strfind(indat,13);              %Find first newline
indat=indat(endheader+1:size(indat,2));   %Extract all characters after first new line
[colA, colB] = strread(indat, '%f %f');   %Convert string to numerical data
0 голосов
/ 10 декабря 2011

Вы можете попытаться ускорить txt2mat, добавив также количество строк заголовка и, если возможно, количество столбцов в качестве входных данных, чтобы обойти анализ файла. Тогда не должно быть коэффициента 25 по сравнению с импортом текстового сканирования с десятичными знаками, разделенными точками. (Вы также можете связаться со мной, используя страницу автора на сайте mathworks.) Пожалуйста, дайте нам знать, если вы найдете более эффективный способ обработки десятичных знаков, разделенных запятыми, в matlab.

0 голосов
/ 20 ноября 2011

Вы можете использовать txt2mat.

A = txt2mat('data.txt');

Он будет обрабатывать данные автоматически.Но вы можете явно сказать:

A = txt2mat('data.txt','ReplaceChar',',.');

PS Это может быть неэффективно, но вы можете скопировать деталь из исходного файла, если она нужна только для ваших конкретных форматов данных.

...