3

我正在尝试加快我在 Matlab 中编写的脚本,该脚本动态地将内存分配给矩阵(基本上从文件中读取一行数据并将其写入矩阵,然后读取另一行并为更大的矩阵分配更多内存存储下一行)。我这样做而不是使用 zeroes() 或其他东西预分配内存的原因是我不知道矩阵需要保持所有数据的确切大小。我也不知道矩阵的最大大小,所以我不能只预先分配一个最大大小然后摆脱我没有使用的内存。这对于少量数据来说很好,但是现在我需要扩展我的脚本以读取数百万个数据点,而这种动态分配的实现实在是太慢了。

所以这是我加快脚本速度的尝试:我尝试使用 zeroes 函数在大块中分配内存,然后一旦块被填满,我就分配另一个大块。这是一些示例代码:

data = [];   
count = 0;

for ii = 1:num_filelines    
   if mod(count, 1000) == 0  
       data = [data; zeroes(1000)];  %after 1000 lines are read, allocate another 1000 line
   end  
   data(ii, :) = line_read(file);  %line_read reads a line of data from 'file'
end

不幸的是,这不起作用,当我运行它时,我收到一条错误消息“错误使用 vertcat 连接的矩阵的维度不一致。”

所以这是我的问题:这种在大块中分配内存的方法实际上是否比增量动态分配更快,以及为什么上面的代码不运行?谢谢您的帮助。

4

3 回答 3

4

我建议做什么,如果您知道行数并且可以猜出足够多的可接受列,请使用sparse matrix.

% create a sparse matrix
mat = sparse(numRows,numCols)

稀疏矩阵不会存储所有零元素,它只存储指向非零索引的指针。这可以帮助节省大量空间。它们的使用和访问与任何其他矩阵相同。仅当您从一开始就确实需要以矩阵格式使用它时。

如果没有,您可以将所有内容都作为cell. 预分配cell array与文件中的行一样多的元素。

data = cell(1,numLines);
% get matrix from line
for i = 1:numLines
    % get matrix from line
    data{i} = lineData;
end
data = cell2mat(data);

此方法会将所有内容放入一个元胞数组中,该元胞数组可以“动态”存储,然后转换为常规矩阵。

添加

如果你正在使用稀疏矩阵方法,一旦你完成了修剪你的矩阵,因为你的矩阵可能会比必要的大,你可以很容易地把它修剪下来,然后将它转换为一个常规矩阵。

[val,~] = max(sum(mat ~= 0,2));
mat(:,val:size(mat,2)) = [];
mat = full(mat); % use this only if you really need the full matrix

这将删除所有不必要的列,然后将其转换为包含 0 个元素的完整矩阵。我不建议将其转换为完整矩阵,因为这需要更多空间,但如果您真的需要它,请使用它。

更新

要轻松获取文件中的行数,请使用 MATLAB 的 perl 解释器

创建一个名为的文件countlines.pl并粘贴在下面的两行中

while (<>) {};
print $.,"\n";

然后你可以在你的文件上运行这个脚本,如下所示

numLines = str2double(perl('countlines.pl','data.csv'));

问题解决了。

从这里的MATLAB 论坛线程

请记住,最好事先预先分配所有内容,因为从技术上讲,在执行 shai 的方法时,您会重新分配大量资源,特别是如果它是一个大文件。

于 2013-08-05T14:36:20.063 回答
1

要解决您的错误,只需在分配时使用此语法

data = [data; zeroes(1000, size(data,2))];

您可能想阅读循环外的第一行,以便了解列数并为data.

于 2013-08-05T14:39:45.153 回答
0

如果你想坚持你写的代码,我会用你的数据初始化来data = []代替

data = zeros(1,1000); 

请记住来自@MZimmerman6 的警告:zeros(1000)生成一个 1000 x 1000 数组。您可能希望将所有zeros语句更改为zeros( ... ,Nc),其中 Nc = 行的长度(以字符为单位)。

于 2013-08-06T11:33:11.467 回答