【问题标题】:Matlab Table / Dataset type optimizationMatlab 表/数据集类型优化
【发布时间】:2017-11-24 13:32:07
【问题描述】:

我正在为 Matlab 中的“观察变量”表搜索一些优化的数据类型,可以通过列(通过变量)和行(通过观察)快速轻松地访问这些数据类型。

这是现有 Matlab 数据类型的比较:

  1. Matrix 非常快,但是,它没有内置的维度索引标签/枚举,而且您不能总是按列索引记住变量名称。
  2. 表格的性能很差,尤其是在 for 循环中读取单个行/列时(我想它会运行一些缓慢的转换方法,并且设计得更像 Excel)。
  3. 标量结构(列数组的结构)数据类型 - 快速按列访问变量作为向量,但按行缓慢转换为观察值。
  4. 非标量结构(结构数组) - 以行方式快速访问作为向量的观测值,但按列方式转换为变量的速度较慢。

我想知道是否可以使用一些更简单和优化的 Table 数据类型版本,如果我只想将行号和列变量索引与仅数字变量 - 或 - 任何变量类型结合起来。

测试脚本结果:

----
TEST1 - reading individual observations
Matrix: 0.072519 sec
Table: 18.014 sec
Array of structures: 0.49896 sec
Structure of arrays: 4.3865 sec
----
TEST2 - reading individual variables
Matrix: 0.0047834 sec
Table: 0.0017972 sec
Array of structures: 2.2715 sec
Structure of arrays: 0.0010529 sec

测试脚本:

Nobs = 1e5; % number of observations-rows
varNames = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'};
Nvar = numel(varNames); % number of variables-colums

M = randn(Nobs, Nvar); % matrix

T = array2table(M, 'VariableNames', varNames); % table

NS = struct; % nonscalar structure = array of structures
for i=1:Nobs
    for v=1:Nvar
        NS(i).(varNames{v}) = M(i,v);
    end
end

SS = struct; % scalar structure = structure of arrays
for v=1:Nvar
    SS.(varNames{v}) = M(:,v);
end

%% TEST 1 - reading individual observations (row-wise)
disp('----'); disp('TEST1 - reading individual observations');

tic; % matrix
for i=1:Nobs
   x = M(i,:); end
disp(['Matrix: ', num2str(toc()), ' sec']);

tic; % table
for i=1:Nobs
   x = T(i,:); end
disp(['Table: ', num2str(toc), ' sec']);

tic;% nonscalar structure = array of structures
for i=1:Nobs
    x = NS(i); end
disp(['Array of structures: ', num2str(toc()), ' sec']);

tic;% scalar structure = structure of arrays 
for i=1:Nobs
    for v=1:Nvar
        x.(varNames{v}) = SS.(varNames{v})(i);
    end
end
disp(['Structure of arrays: ', num2str(toc()), ' sec']);

%% TEST 2 - reading individual variables (column-wise)
disp('----'); disp('TEST2 - reading individual variables');

tic; % matrix
for v=1:Nvar
   x = M(:,v); end
disp(['Matrix: ', num2str(toc()), ' sec']);

tic; % table
for v=1:Nvar
   x = T.(varNames{v}); end
disp(['Table: ', num2str(toc()), ' sec']);

tic; % nonscalar structure = array of structures
for v=1:Nvar
    for i=1:Nobs
        x(i,1) = NS(i).(varNames{v});
    end
end
disp(['Array of structures: ', num2str(toc()), ' sec']);

tic; % scalar structure = structure of arrays
for v=1:Nvar
    x = SS.(varNames{v}); end
disp(['Structure of arrays: ', num2str(toc()), ' sec']);

【问题讨论】:

  • 应使用timeit 进行计时以获得准确的结果。此外,只需使用矩阵并在上面/后面/下面或列包含的某处添加评论。在通常是第一个评论部分的一部分的函数中,即当您键入 help FunctionName 时得到的函数
  • 我已经检查过了,并用timeit 定时给出或多或少相同的结果。
  • 我原以为 gnovice 的容器。地图解决方案会适合您的喜好。这是我对这个问题的最初反应。我唯一能想到的另一件事是扩展一个像 struct 这样的基本类。

标签: matlab matrix data-structures dataset tuples


【解决方案1】:

我会使用矩阵,因为它们是最快且最简单易用的,然后创建一组枚举列标签以使索引列更容易。这里有几种方法可以做到这一点:


使用containers.Map 对象:

给定您的变量名称,并假设它们按从第 1 列到 N 的顺序映射,您可以像这样创建映射:

varNames = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'};
col = containers.Map(varNames, 1:numel(varNames));

现在您可以使用地图通过变量名称访问数据列。例如,如果您想从矩阵 data 中获取变量 AC(即第一和第三)的列,您可以这样做:

subData = data(:, [col('A') col('C')]);


使用struct:

您可以创建一个结构,将变量名称作为其字段,并将相应的列索引作为其值,如下所示:

enumData = [varNames; num2cell(1:numel(varNames))];
col = struct(enumData{:});

col 包含以下内容:

struct with fields:

  A: 1
  B: 2
  C: 3
  D: 4
  E: 5
  F: 6
  G: 7
  H: 8
  I: 9
  J: 10
  K: 11
  L: 12
  M: 13
  N: 14
  O: 15

您可以像这样访问AC 列:

subData = data(:, [col.A col.C]);
% ...or with dynamic field names...
subData = data(:, [col.('A') col.('C')]);


制作一堆变量:

可以在工作区中为每个列名创建一个变量,并将列索引存储在其中。这将用更多变量污染您的工作区,但为您提供了一种访问列数据的简洁方式。这是一个简单的方法,使用备受诟病的eval

enumData = [varNames; num2cell(1:numel(varNames))];
eval(sprintf('%s=%d;', enumData{:}));

访问AC 列非常简单:

subData = data(:, [A C]);


使用enumeration class

这可能有点过头了,但是如果您要为 许多 分析使用相同的列标签和索引映射,您可以创建一个枚举类,将其保存在您的某个位置MATLAB path,永远不必担心再次定义列枚举。例如,这是一个有 15 个枚举值的 ColVar 类:

classdef ColVar < double
  enumeration
    A (1)
    B (2)
    C (3)
    D (4)
    E (5)
    F (6)
    G (7)
    H (8)
    I (9)
    J (10)
    K (11)
    L (12)
    M (13)
    N (14)
    O (15)
  end
end

您可以像这样访问AC 列:

subData = data(:, [ColVar.A ColVar.C]);

【讨论】:

  • 感谢您提供有趣的解决方案!但在所有这些情况下,我将为枚举列标签和数据集本身提供不同的 matlab 变量。我尝试从内置的 Matlab 双类继承并添加一个属性或枚举来保存变量名称,但它不起作用:“当内置类的子类定义属性时,MATLAB 不再支持索引和串联操作”mathworks.com/help/matlab/matlab_oop/…
  • @Sairus:没错,子类化内置数据类型可能会降低效率,因为您必须自己实现索引和连接方法(在您的链接中列出)。不过,我不清楚为什么这些选项还不够好。如果效率至关重要,一个简单的矩阵似乎就是您想要的,唯一的问题是记住哪个列标签映射到哪个索引。上述解决方案应该可以省去您的麻烦。
  • 我正在开发一个系统,该系统按顺序处理许多数据集的一堆信号,并且将许多标签传递给每个处理函数是非常尴尬的。或者,我可以编写数据存储类,它包含您答案中的原始矩阵和标签结构,具有获取和设置方法(使用写时复制应该足够快)。但是我的功能将取决于那个“核心”类结构。但是,我认为这是现有 Matlab 数据类型需要解决的一个更常见的问题。
猜你喜欢
  • 1970-01-01
  • 2019-11-21
  • 1970-01-01
  • 2018-12-14
  • 1970-01-01
  • 2011-11-15
  • 2016-03-14
  • 1970-01-01
  • 2019-09-24
相关资源
最近更新 更多