5

我有以下关于大型文本文件输入(~500k 行)和后续数据解析的性能问题

考虑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})尽管str2doublestr2num. 第二个最慢的部分是textscan.

现在的问题是,有没有更快的方法来处理这个问题?

请让我知道我是否应该进一步澄清。如果有一个我没有看到的非常明显的解决方案,请原谅我,我现在才使用 Matlab 工作了三周。

4

2 回答 2

4

您可以使用textscan调用选项,该选项CommentStyle将跳过部分文件(在您的情况下重复的 2 个标题行),并在一个函数调用中读取您的文件。

正如文档所说CommentStyle可以以两种方式使用:单个字符串,例如'%'忽略同一行上的字符串后面的字符,或两个字符串的元胞数组,例如{'/*', '*/'}忽略两个字符串之间的字符(包括行)。我们将在这里使用第二个选项:删除 和 之间的Name字符-。由于结束字符串由重复-字符组成,我们需要指定整个字符串。

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

您可以使用 将日期字符串转换为有意义的数字datenum

DATA_date = datenum(C{2})
于 2013-10-03T15:21:41.663 回答
2

尽管从长远来看,如果可以修复数据采集以避免这种情况会更好,但您可以利用HeaderLinestextscan。

此示例代码将起作用,但如果可能,请预先分配 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
于 2013-10-03T14:55:58.960 回答