Matlab:如何读取逗号作为小数分隔符的数字?

5
我有大量(成百上千)的相当大(> 0.5MB)文件,其中数据是数值,但逗号作为小数分隔符。对于我来说,使用类似于sed“s /,/。/ g”的外部工具是不切实际的。当分隔符是点时,我只需使用textscan(fid,'%f%f%f'),但我看不到更改小数分隔符的选项。如何以高效的方式读取这样的文件?
文件中的示例行:
5,040000    18,040000   -0,030000

注意:这里有一个R语言相关的类似问题,但我使用Matlab。

4个回答

4

通过测试脚本,我发现一个小于1.5的因子。我的代码如下:

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

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

请注意'ReplaceChar'值和'ReadMode'的块不同。
在我的(不是很新的)机器上,对于一个约5MB的文件,我得到以下结果:
- txt2mat测试逗号平均时间: 0.63231 - txt2mat测试点平均时间: 0.45715 - textscan测试点平均时间: 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('-----')

因为txt2mat的开销更大,所以对于较小的文件,该因子将会增加。但是即使对于0.5MB的文件,我的结果也不到2。 - Andres

0

您可以尝试通过将头行数和列数作为输入添加到txt2mat中来加速它的处理速度,如果可能的话,以绕过其文件分析。这样就不会与使用点分隔小数的textscan导入相比存在25倍的差距了。(您也可以使用mathworks网站上的作者页面与我联系。)如果您发现了更有效的处理matlab中逗号分隔小数的方法,请告诉我们。


嗯,它仍然慢得多。与使用点分隔的数字进行的“textscan”导入相比,我实现了20倍的速度。我使用了以下公式:txt2mat(filename, 'InfoLevel', 0, 'ReplaceChar', {',', '.'}, 'NumHeaderLines', 1, 'ConvString', repmat('%f', 1,5), 'NumColumns', 5); - Marek Kurdej

0

你可以使用txt2mat

A = txt2mat('data.txt');

它会自动处理数据。但你也可以明确地说明:

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

顺便说一句,这可能不是很高效,但如果您只需要针对特定数据格式进行操作,可以从源文件中复制该部分。


嗯,效率在这里实际上非常重要。而且“txt2mat”比“textscan”慢大约25倍。 - Marek Kurdej
我明白了 :( 是否使用正则表达式转换会有帮助,就像这里讨论的一样:http://www.mathworks.cn/matlabcentral/newsreader/view_thread/239684#612432 - petrichor

0

我的解决方案(假设逗号仅用作小数点,空格分隔列):

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接