从文本文件中将数据读入MATLAB

时间:2009-09-29 12:33:06

标签: matlab file-io text-files

我有一个具有以下结构的文本文件:

1999-01-04
1,100.00
1,060.00
1,092.50
0
6,225
1,336,605
37
1999-01-05 
1,122.50
1,087.50
1,122.50
0
3,250
712,175
14
...

该文件包含重复的八个值集合(一个日期后面跟着七个数字,每个都在各自的行上)。

我想把它读入MATLAB并将值放到不同的向量中。我试图用几种不同的方法来实现这一点,但没有一种方法有效 - 都输出了某种错误。

如果它很重要,我在Mac上这样做。

6 个答案:

答案 0 :(得分:9)

编辑:这是我之前在答案中的代码的简短版本......

如果您想直接读取数据文件,而不必先将其预处理为dstibbe suggested,则以下内容应该有效:

fid = fopen('datafile.txt','rt');
data = textscan(fid,'%s %s %s %s %s %s %s %s','Delimiter','\n');
fclose(fid);
data = [datenum(data{1}) cellfun(@str2double,[data{2:end}])]';

上面的代码将每组8个值放入8×N矩阵中,N是数据文件中8个线组的数量。日期将转换为序列日期编号,以便它可以包含在矩阵中的其他双精度值中。以下函数(在上面的代码中使用)可能很有用:TEXTSCANDATENUMCELLFUNSTR2DOUBLE

答案 1 :(得分:4)

我提出另一个解决方案。这是MATLAB代码中最短的一个。首先使用 sed ,我们将文件格式化为CSV文件(逗号分隔,每行记录在一行):

cat a.dat | sed -e 's/,//g ; s/[ \t]*$/,/g' -e '0~8 s/^\(.*\),$/\1\n/' | 
            sed -e :a -e '/,$/N; s/,\n/,/; ta' -e '/^$/d' > file.csv

解释:首先我们删除了数千个逗号分隔符,并在每行末尾修剪空格添加逗号。但是我们删除每个第8行的结尾逗号。最后,我们加入这些行并删除空行。

输出将如下所示:

1999-01-04,1100.00,1060.00,1092.50,0,6225,1336605,37
1999-01-05,1122.50,1087.50,1122.50,0,3250,712175,14

接下来在MATLAB中,我们只需使用 textscan 来读取每一行,第一个字段为字符串(转换为num),其余为数字:

fid = fopen('file.csv', 'rt');
a = textscan(fid, '%s %f %f %f %f %f %f %f', 'Delimiter',',', 'CollectOutput',1);
fclose(fid);

M = [datenum(a{1}) a{2}]

,得到的矩阵M为:

  730124     1100     1060   1092.5    0   6225   1336605    37
  730125   1122.5   1087.5   1122.5    0   3250    712175    14

答案 2 :(得分:3)

使用脚本将文本文件修改为Matlab可以读取的内容。

例如。把它变成一个矩阵:

M = [
1999-01-04
1,100.00
1,060.00
1,092.50
0
6,225
1,336,605;  <-- notice the ';'
37
1999-01-05 
1,122.50
1,087.50
1,122.50
0
3,250;   <-- notice the ';'
712,175
14
...
]

将其导入matlab并从矩阵中读取各种向量。

注意:我的matlab有点生疏。可能包含错误。

答案 3 :(得分:2)

一旦您阅读完数据,您希望数据的形式并不完全清楚。下面的代码将它全部放在一个矩阵中,每行代表文本文件中的一组8行。您可能希望对不同的列使用不同的变量,或者(如果您可以访问统计工具箱),请使用数据集数组。

% Read file as text
text = fileread('c:/data.txt');

% Split by line
x = regexp(text, '\n', 'split');

% Remove commas from numbers
x = regexprep(x, ',', '')

% Number of items per object
n = 8;

% Get dates
index = 1:length(x);
dates = datenum(x(rem(index, n) == 1));

% Get other numbers
nums = str2double(x(rem(index, n) ~= 1));
nums = reshape(nums, (n-1), length(nums)/(n-1))';

% Combine dates and numbers
thedata = [dates nums];

您还可以查看函数textscan以了解解决问题的其他方法。

答案 4 :(得分:0)

与Richie相似。使用str2double将文件字符串转换为双精度数。此实现逐行处理,而不是使用正则表达式打破文件。输出是各个向量的单元格数组。

function vectors = readdata(filename)

fid=fopen(filename);

tline = fgetl(fid);
counter = 0;
vectors = cell(7,1);
while ischar(tline)
    disp(tline)
    if counter > 0
        vectors{counter} = [vectors{counter} str2double(tline)];
    end
    counter = counter + 1
    if counter > 7
        counter = 0;
    end
    tline = fgetl(fid);
end

fclose(fid);

答案 5 :(得分:0)

这有正则表达式检查,以确保您的数据格式良好。

fid = fopen('data.txt','rt');

%these will be your 8 value arrays
val1 = [];
val2 = [];
val3 = [];
val4 = [];
val5 = [];
val6 = [];
val7 = [];
val8 = [];

linenum = 0; % line number in file
valnum = 0; % number of value (1-8)

while 1
   line = fgetl(fid);
   linenum = linenum+1;
   if valnum == 8
      valnum = 1;
   else
      valnum = valnum+1;
   end

    %-- if reached end of file, end
    if isempty(line) | line == -1
      fclose(fid);
      break;
   end


   switch valnum
      case 1
         pat = '(?\d{4})-(?\d{2})-(?\d{2})'; % val1 (e.g. 1999-01-04)
      case 2
         pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val2 (e.g. 1,100.00)  [valid up to 1billion-1]
      case 3
         pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val3 (e.g. 1,060.00)  [valid up to 1billion-1]
      case 4
         pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val4 (e.g. 1,092.50)  [valid up to 1billion-1]
      case 5
         pat = '(?\d+)'; % val5 (e.g. 0)
      case 6
         pat = '(?\d*[,]*\d*[,]*\d+)'; % val6 (e.g. 6,225)  [valid up to 1billion-1]
      case 7
         pat = '(?\d*[,]*\d*[,]*\d+)'; % val7 (e.g. 1,336,605)  [valid up to 1billion-1]
      case 8
         pat = '(?\d+)'; % val8 (e.g. 37)
      otherwise
         error('bad linenum')
   end

   l = regexp(line,pat,'names'); % l is for line
    if length(l) == 1 % match
      if valnum == 1
         serialtime = datenum(str2num(l.yr),str2num(l.mo),str2num(l.dy)); % convert to matlab serial date
         val1 = [val1;serialtime];
      else
         this_val = strrep(l.val,',',''); % strip out comma and convert to number
         eval(['val',num2str(valnum),' = [val',num2str(valnum),';',this_val,'];']) % save this value into appropriate array
      end
   else
      warning(['line number ',num2str(linenum),' skipped! [didnt pass regexp]: ',line]);
   end
end