2013-08-05 26 views
2

我想加快我写在Matlab中的动态分配内存到矩阵的脚本(基本上是从文件读取一行数据并将其写入矩阵,然后读取另一行并为更大的矩阵分配更多内存以存储下一行)。我之所以这么做,是因为我不知道矩阵需要保存所有数据的确切大小,而不是使用零()或者其他的预分配内存。我也不知道矩阵的最大尺寸,所以我不能预先分配最大尺寸,然后摆脱我没有使用的内存。这对于少量数据来说很好,但现在我需要扩展脚本以读取数百万个数据点,而这种动态分配的实现速度太慢了。最大尺寸未知时MatLab内存分配

所以这里是我加速脚本的尝试:我尝试使用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矩阵 尺寸误差并不一致。”

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

+2

当你做零(1000)时,你正在分配一个1000x1000的零矩阵。这可能是你的代码没有运行的原因。至于分配速度,在matlab中预先分配总是好的,但是在读取行时不是使用数组,而是使用单元格来存储数据。这样你就没有太多问题。要么,要么使用稀疏矩阵。 – MZimmerman6

+0

这将取决于您使用的Matlab版本。最近的版本在动态内存分配方面表现得非常快。 [阅读更多](http://undocumentedmatlab.com/blog/array-resizing-performance/)。 – horchler

回答

3

我推荐做什么,如果您知道行数并且可以猜测足够大的可接受列数,请使用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个元素的完整矩阵。我不建议把它铸造成一个完整的矩阵,因为这需要更多的空间,但如果你确实需要它,就使用它。

UPDATE

要获得文件的行数容易,使用MATLAB的Perl的interpretter

创建一个名为countlines.pl,并在两行粘贴下面

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

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

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

问题解决。

从MATLAB论坛主题here

记住它始终是最好的预分配前手的一切,因为从技术上做晒的方法,当你重新分配大量的很多,尤其是如果它是一个大的文件。

+0

您可能想要通过“guessin”/估计非零的数量为稀疏矩阵中的非零保留空间 – Shai

+0

@Shai我不确定您的意思,稀疏矩阵将处理分配以及其他任何您。 – MZimmerman6

+0

我的问题还不够清楚,但实际上我不知道我需要多少行。 Shai对我发布的代码的修复解决了我的问题,并极大地加快了我的脚本速度。感谢使用稀疏()和指针的建议,但我没有想到这一点。现在我的问题已经解决了,我很好奇,我的方法是否与数据行数成线性比例,还是比动态添加新行好得多?我想我不明白为什么在块中分配内存效率更高 – dynamo

1

解决您的错误,只需分配

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

时使用此语法,你可能需要阅读的第一行外循环,让您知道的列数,使第一分配data

+0

是的,这是错误的,没有输入正确数量的零列矩阵,oops。我碰巧知道需要多少列,而行数是未知的,但单独阅读第一行也是使脚本更加普遍化的一个好主意,谢谢。 – dynamo

0

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

data = zeros(1,1000); 

请记住,虽然来自@ MZimmerman6警告:zeros(1000)生成1000×1000阵列。您可能需要将所有zeros语句更改为zeros(... ,Nc),其中Nc =字符长度。