用于混合类型的Matlab数据结构-时间和空间效率如何?

标签 matlab performance data-structures large-data bigdata

我需要处理大量混合类型的表格数据-字符串和 double 型。我认为这是一个标准的问题。 Matlab中与此相关的最佳数据结构是什么?

细胞阵列绝对不是答案。这是极其低效的内存。 (测试如下所示)。数据集(来自统计信息工具箱)的时间和空间效率非常低。这让我留下了structarray或数组的struct。我在下面的时间和内存方面对所有四个不同的选项进行了测试,在我看来,数组结构是我所测试的东西的最佳选择。

坦白说,我对Matlab来说还比较陌生,这有点令人失望。无论如何-寻找有关我是否缺少某些东西或我的测试是否正确/合理的建议。除了访问/转换/内存使用之外,我是否还缺少其他考虑因素,因为在我使用这些东西编写更多代码时,这些因素可能还会出现。 (仅供引用,请使用R2010b)

**测试1:访问速度访问数据项。

cellarray:0.002s
dataset:36.665s       %<<< This is horrible
structarray:0.001s
struct of array:0.000s

**测试2:转换速度和内存使用情况我从该测试中删除了数据集。
Cellarray(doubles)->matrix:d->m: 0.865s
Cellarray(mixed)->structarray:c->sc: 0.268s
Cellarray(doubles)->structarray:d->sd: 0.430s
Cellarray(mixed)->struct of arrays:c->sac: 0.361s
Cellarray(doubles)->struct of arrays:d->sad: 0.887s
  Name           Size               Bytes  Class     Attributes
    c         100000x10            68000000  cell                
    d         100000x10            68000000  cell                
    m         100000x10             8000000  double              
    sac            1x1             38001240  struct              
    sad            1x1              8001240  struct              
    sc        100000x1             68000640  struct              
    sd        100000x1             68000640  struct  

==================代码:TEST#1
  %% cellarray
  c = cell(100000,10);
  c(:,[1,3,5,7,9]) = num2cell(zeros(100000,5));
  c(:,[2,4,6,8,10]) = repmat( {'asdf'}, 100000, 5);
  cols = strcat('Var', strtrim(cellstr(num2str((1:10)'))))';
  te = tic;
  for iii=1:1000
      x = c(1234,5);
  end
  te = toc(te);
  fprintf('cellarray:%0.3fs\n', te);
  %% dataset
  ds = dataset( { c, cols{:} } );
  te = tic;
  for iii=1:1000
      x = ds(1234,5);
  end
  te = toc(te);
  fprintf('dataset:%0.3fs\n', te);
  %% structarray
  s = cell2struct( c, cols, 2 );
  te = tic;
  for iii=1:1000
      x = s(1234).Var5;
  end
  te = toc(te);
  fprintf('structarray:%0.3fs\n', te);
  %% struct of arrays
  for iii=1:numel(cols)
      if iii/2==floor(iii/2) % even => string
          sac.(cols{iii}) = c(:,iii);
      else
          sac.(cols{iii}) = cell2mat(c(:,iii));
      end
  end
  te = tic;
  for iii=1:1000
      x = sac.Var5(1234);
  end
  te = toc(te);
  fprintf('struct of array:%0.3fs\n', te);

==================代码:测试#2
%% cellarray
% c - cellarray containing mixed type 
c = cell(100000,10);
c(:,[1,3,5,7,9]) = num2cell(zeros(100000,5));
c(:,[2,4,6,8,10]) = repmat( {'asdf'}, 100000, 5);
cols = strcat('Var', strtrim(cellstr(num2str((1:10)'))))';
% c - cellarray containing doubles only
d = num2cell( zeros( 100000, 10 ) );
%% matrix
% doubles only
te = tic;
m = cell2mat(d);
te = toc(te);
fprintf('Cellarray(doubles)->matrix:d->m: %0.3fs\n', te);
%% structarray
% mixed
te = tic;
sc = cell2struct( c, cols, 2 );
te = toc(te);
fprintf('Cellarray(mixed)->structarray:c->sc: %0.3fs\n', te);
% doubles
te = tic;
sd = cell2struct( d, cols, 2 );
te = toc(te);
fprintf('Cellarray(doubles)->structarray:d->sd: %0.3fs\n', te);
%% struct of arrays
% mixed
te = tic;
for iii=1:numel(cols)
    if iii/2==floor(iii/2) % even => string
        sac.(cols{iii}) = c(:,iii);
    else
        sac.(cols{iii}) = cell2mat(c(:,iii));
    end
end
te = toc(te);
fprintf('Cellarray(mixed)->struct of arrays:c->sac: %0.3fs\n', te);
% doubles
te = tic;
for iii=1:numel(cols)
    sad.(cols{iii}) = cell2mat(d(:,iii));
end
te = toc(te);
fprintf('Cellarray(doubles)->struct of arrays:d->sad: %0.3fs\n', te);
%% 
clear iii cols te;
whos

最佳答案

使Matlab代码在时间和空间上都高效的方法是使用大型原语数组-即double,int或chars数组。这样可以使您在内存中的布局更紧凑,并可以执行矢量化操作。

对于表格数据,每列的类型将是相同的,但是不同的列可能具有不同的类型,并且通常您的行要多于列。而且,您通常会在列的所有元素上进行比较或数学运算,或者对列进行掩盖选择,这很容易进行矢量化运算。因此,将每个列存储为一个列数组,希望包含原语。您可以将这些列粘贴在结构的字段或单元格向量的元素中;性能无关紧要,并且struct形式将更具可读性,并且看起来更像是一个表。将所有元素分解成自己的小型mxarray的二维单元阵列或其他数据结构将无法正确执行。

也就是说,如果您有一个10,000行乘10列的表,则希望有一个10长的单元格数组或10字段的结构,这些字段或元素中的每一个都持有10,000长的原始列向量。
dataset对象对象基本上是包裹在对象中的如前所述的列数组结构的包装器。但是Matlab中的对象比常规结构和单元具有更大的开销。您需要为每次访问支付一个或多个方法调用。看看Is MATLAB OOP slow or am I doing something wrong?(完整披露:这是我的答案之一)。

您设置的测试并不表示Matlab代码的性能如何,因为它正在执行标量单元素访问。也就是说,每次循环都要为列和行元素访问付费。如果您的Matlab代码正在执行此操作,则说明您已经不走运了。为快速起见,您需要在循环外部弹出列-也就是说,将昂贵的列访问操作提升到外部循环或设置代码-然后执行矢量化操作(例如+==,'<',ismember,等等)在整个列向量上循环,或在原始数值向量(JIT可以优化的原始向量)上循环。如果执行此操作,则dataset和其他基于对象的表格结构可以具有不错的性能。

不幸的是,Matlab中的字符串有点烂。您想摆脱cellstrs。您有几种选择。

  • 如果列中的字符串长度大约相同,并且其中没有长字符串,则可以将字符串向量存储为二维char数组。这是内存中的单个连续数组,比单元数组具有更高的空间效率,并且在比较操作等方面可能更快。它也是Matlab的 native 字符串表示形式之一,因此普通的字符串函数都可以使用它。
  • 如果字符串的基数较低(即,相对于元素总数而言,不同值的数量较小),则可以将它们编码为“符号”,并将它们存储为原始int数组,这些原始int索引到a不同字符串值的列表。 uniqueismember函数可以帮助实现这些编码。只要您只是在进行相等性测试而不是进行排序,这些编码的字符串列都将以数字速度运行。
  • 我相信其中一个工具箱(也许是带有dataset的工具箱)支持“分类器”或“类别”变量,它们基本上是该低基数编码的现成实现。
  • 不用理会Java字符串。跨越Matlab-to-Java障碍的开销将使其净亏损。
  • 希望现在有人提出了其他建议。

  • 如果必须坚持使用cellstr,则将它们作为cellstr列向量存储在如上所述的结构内部;这样,您只需要在实际操作字符串列时支付单元格访问的费用即可。

    关于用于混合类型的Matlab数据结构-时间和空间效率如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16243523/

    相关文章:

    performance - session 中对象过多时提高 NHibernate 性能

    java - (Java) 快速插入、删除和随机选择的数据结构

    c++ - 存储各种尺寸也各不相同的结构的好方法?

    data-structures - 纯功能等效于弱 HashMap ?

    excel - 相同的公式,但在 Matlab 和 Excel 中的结果不同

    matlab - 如何比较matlab细胞或结构

    matlab - 我们需要预先分配。但是MATLAB没有预分配预分配?

    java - 如何调整 wicket 应用程序的性能

    java - 在Java中搜索堆栈中最大元素的最快方法是什么?

    matlab - 将 3d 坐标存储在点列表中 Matlab