Matlab - 读取不同行长的文件

时间:2014-05-08 20:44:26

标签: matlab nan text-processing

我有一个数据文件,每行数据量不一,我想将其作为数组加载到Matlab中。例如,假设数据文件看起来像

1 2
3 4 5 6
7
8 9 10

我想把它作为一个看起来像

的数组读入Matlab
1  2  nan nan
3  4   5   6
7 nan nan nan
8  9  10  nan

我可以通过在文件的所有行上执行for循环来完成此操作,但我的文件非常大,我正在寻找一个有效的解决方案。任何想法都将受到高度赞赏。如果有帮助,我也知道文件中最大行长的上限。

3 个答案:

答案 0 :(得分:2)

案例1:没有零的数据

此技术使用 dlmread ,它固有地将空位置转换为零,然后我们需要根据需要将这些位置转换为NaN以获得所需的输出。

<强>代码

out = dlmread(textfile_path, ' ') %%// textfile_path is path to your text file
out(out==0)=NaN %%// out is your desired output

<强>输入

1 2
3 4 5 6
7
8 9 10

<强>输出

out =
     1     2   NaN   NaN
     3     4     5     6
     7   NaN   NaN   NaN
     8     9    10   NaN

案例2:带零的数据因此需要特别注意保留这些零

这种方法围绕使用 textscan 将数据导入到按原样保留零的单元格列数组,并将空位置作为NaN。唯一的问题是,对于最后一行,由于没有任何空位(如果最后一行不是最长的一行),则长度不等于行数。同样,我们需要额外的代码行。

方法1:

<强>代码

fid = fopen(textfile_path,'r');  %%// textfile_path is path to your text file
data1 = textscan(fid,'');
fclose(fid);

lens = cellfun(@numel,data1)
out = NaN(max(lens),numel(lens))  %%// out will be your output
for k = 1:numel(lens)
    out(1:lens(k),k) = data1{:,k}
end

方法2(更短版本):

<强>代码

fid = fopen(textfile_path,'r');  %%// textfile_path is path to your text file
data1 = textscan(fid,'');
fclose(fid);

n1 = find(diff(cellfun(@numel,data1))~=0)

%%// out will be your output
out = [horzcat(data1{:,[1 n1]}) [horzcat(data1{:,[n1+1:end]}) ; NaN(1,numel(data1)-n1)]]

<强>输入

1 2 3
4 0
5 6 0 7 8
0 0

<强>输出

out =
     1     2     3   NaN   NaN
     4     0   NaN   NaN   NaN
     5     6     0     7     8
     0     0   NaN   NaN   NaN

答案 1 :(得分:2)

虽然如果您的文本文件中没有任何零值,Divakar的答案仍然有效,但通常情况并非如此。例如,如果您的文本数组是

1 2 3
4 0
5 6 0 7 8
然后Divakar的结果将是:

1 2 3 nan nan
4 nan nan nan nan
5 6 nan 7 8

而你真的想要:

1 2 3 nan nan
4 0 nan nan nan
5 6 0 7 8

实现这一点的最简单方法是打开dlmread函数(只需在文本编辑器中键入dlmread并按Ctrl + D将其打开)。请确保将此文件另存为您使用其他名称(即dlmread_nan.m)工作的目录中的单独文件。

转到代码的这一部分(我的版本中的第126行):

if isempty(delimiter)
    result  = textscan(fid,'',nrows,'headerlines',r,'headercolumns',c,...
                       'returnonerror',0,'emptyvalue',0, 'CollectOutput', true);
else
    delimiter = sprintf(delimiter);
    whitespace  = setdiff(sprintf(' \b\t'),delimiter);
    result  = textscan(fid,'',nrows,...
                   'delimiter',delimiter,'whitespace',whitespace, ...
                   'headerlines',r,'headercolumns',c,...
                   'returnonerror',0,'emptyvalue',0,'CollectOutput', true);
end

并在&#39; emptyvalue&#39;之后更改值在两种情况下都是NaN而不是0.保存文件。它应该是这样的:

if isempty(delimiter)
    result  = textscan(fid,'',nrows,'headerlines',r,'headercolumns',c,...
                       'returnonerror',0,'emptyvalue',NaN, 'CollectOutput', true);
else
    delimiter = sprintf(delimiter);
    whitespace  = setdiff(sprintf(' \b\t'),delimiter);
    result  = textscan(fid,'',nrows,...
                   'delimiter',delimiter,'whitespace',whitespace, ...
                   'headerlines',r,'headercolumns',c,...
                   'returnonerror',0,'emptyvalue',NaN,'CollectOutput', true);
end

要获取数组,请使用:

result = dlmread_nan('text.txt', ' '); 
%%//This will give you exactly what you're looking for.

这有点麻烦,但是通过从MATLAB库中复制,它可能比自己从头开始编写更加强大和无错误。

答案 2 :(得分:0)

在这种情况下?

<强>输入

1 2 3   6
4   5
1   0 7 8
0 0     5

怎么办?

Textscan会很危险,因为它不会保留数字位置