从文本文件到稀疏矩阵的Matlab转换。

4

I have a huge text file in the following format:

1   2
1   3
1   10
1   11
1   20
1   376
1   665255
2   4
2   126
2   134
2   242
2   247

第一列是x坐标,而第二列是y坐标。 这意味着如果我需要构建一个矩阵

M = zeros(N, N);
M(1, 2) = 1;
M(1, 3) = 1;
.
.
M(2, 247) = 1;

这个文本文件非常大,无法一次性加载到内存中。我必须逐行读取并将其保存在一个稀疏矩阵中。

因此,我需要以下功能:

function mat = generate( path )
    fid = fopen(path);
    tline = fgetl(fid);
    % initialize an empty sparse matrix. (I know I assigned Mat(1, 1) = 1)
    mat = sparse(1);
    while ischar(tline)
        tline = fgetl(fid);
        if ischar(tline)
            C = strsplit(tline);
        end
        mat(C{1}, C{2}) = 1;
    end
    fclose(fid);
end

不幸的是,除了第一行之外,它只会在我的稀疏矩阵中放入垃圾。 演示:

1 7
1 9
2 4
2 9

如果我打印稀疏矩阵,我会得到以下结果:
   (1,1)        1
  (50,52)       1
  (49,57)       1
  (50,57)       1

有什么建议吗?

我猜你需要使用 str2double()C{1}C{2} 转换为数字。但是,如果坐标文件太大无法加载到内存中,那么构建的稀疏数组也很可能会太大。我认为 MATLAB 在内部使用压缩稀疏列表示法,这比一组坐标点更占空间... - Justin
@Justin 对不起,文件大小是500MB。我的意思是我无法将其在普通矩阵中打开,然后再将其稀疏化,因为它太大了。我需要通过逐行读取来构建稀疏矩阵。 - Tony
@TonyTannous:一个小建议:由于path是一个内置函数,您不应该将其用作变量名。 - gnovice
@gnovice 感谢您的回答和建议。 - Tony
1个回答

4

修复问题...

你的问题在于C是一个字符数组的元胞数组,而不是数字。你需要将从文件中读取的字符串转换为整数值。你可以使用像str2numstr2double这样的函数,而不是strsplit。在这种情况下,由于tline是一个以空格分隔的整数字符数组,因此str2num是计算C最容易使用的方法:

C = str2num(tline);

然后,您只需像数组一样索引 C,而不是单元数组:
mat(C(1), C(2)) = 1;
额外信息:如果你想知道即使C包含字符,为什么你的演示代码仍然有效,那是因为MATLAB有时会自动将变量转换为某些操作的正确类型。在这种情况下,这些字符被转换为它们的double ASCII码等价值:'1'变成了49'2'变成了50等等。然后将它们用作mat的索引。


更简单的替代方案...

你甚至不需要烦恼上面所有的麻烦,因为你可以使用dlmreadsparse来替换整个函数,就像这样:

data = dlmread(filePath);
mat = sparse(data(:, 1), data(:, 2), 1);
clear data;  % Save yourself some memory if you don't need it any more

顺便提一下,str2num 使用 eval 进行转换。你可能想使用 str2double 代替。 - Sardar Usama
@SardarUsama:但是对于由空格分隔的数字字符串无效。例如,str2double('1 2 3')会返回NaN - gnovice
使用strsplit如何?如果a='1 2 3 4',那么str2double(strsplit(a)) - Sardar Usama
无法处理大文件 :( ones 会在内存中爆炸。 - Tony
@TonyTannous:我去掉了对ones的依赖并添加了一个clear调用,但即便如此,你仅仅使用那个就出现内存错误的事实让我认为你可能有太多行数据,无论使用稀疏矩阵进行下一步的计算,仍会导致内存错误。 - gnovice

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