结构的Matlab数组:快速分配

Posted

技术标签:

【中文标题】结构的Matlab数组:快速分配【英文标题】:Matlab array of struct : Fast assignment 【发布时间】:2011-12-17 02:04:17 【问题描述】:

有没有办法“向量”分配一个结构数组。

目前可以

edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A.
for i=1:1000000; edges(i).weight=1.0; end; 

但这很慢,我想做一些类似的事情

edges(:).weight=[rand(1000000,1)]; //with or without the square brackets. 

对此分配进行矢量化的任何想法/建议,以便它更快。

提前致谢。

【问题讨论】:

这篇文章可能会有所帮助:***.com/questions/4166438/… 【参考方案1】:

这比交易或循环快得多(至少在我的系统上):

N=10000;
edge(N) = struct('weight',1.0); % initialize the array
values = rand(1,N);  % set the values as a vector

W = mat2cell(values, 1,ones(1,N)); % convert values to a cell
[edge(:).weight] = W:;

使用右边的花括号给出 W 中所有值的逗号分隔值列表(即 N 个输出),并在右边使用方括号将这 N 个输出分配给 edge(:).weight 中的 N 个值。

【讨论】:

不错!语法和语用优雅!如果 Matlab 语法允许将数组扩展为参数序列,例如“values:”,那就太好了。尝试制作一个函数来获取单元格值列表,但显然它不喜欢以与 deal() 完全相同的方式分配给 varargout 哈哈。 糟糕,发现我使用的是mat2cell() 而不是num2cell()。这是函数:cellexpand(). 您也可以使用匿名句柄:cellexpand = @(x) x:; numexpand = @(x) cellexpand(num2cell(x));。一个例子:[a, b] = numexpand([1, 2]);。更具体的例子:[edge.weight] = numexpand([edge.weight] + 50);【参考方案2】:

您可以尝试使用 Matlab 函数 deal,但我发现它需要稍微调整输入(使用这个问题:In Matlab, for a multiple input function, how to use a single input as multiple inputs?),也许有更简单的东西。

n=100000;
edges(n)=struct('weight',1.0);
m=mat2cell(rand(n,1),ones(n,1),1);
[edges(:).weight]=deal(m:);

我还发现,这并不像我计算机上的 for 循环那么快(约 0.35 秒用于交易,而约 0.05 秒用于循环)大概是因为调用了mat2cell。如果您多次使用它,速度差异会减小,但它仍然有利于 for 循环。

【讨论】:

这是我的时代。在 Octave 上:100K 为 0.17 秒,10 万为 1.57 秒,如果我使用 for 循环,则需要永远,比如 100K 需要 230 秒。 MATLAB 2009B(差异机器/OS):5s/49s 使用上面和 .22s/2.2s 使用 for 循环。【参考方案3】:

你可以简单地写:

edges = struct('weight', num2cell(rand(1000000,1)));

【讨论】:

【参考方案4】:

有什么要求你特别以这种方式使用结构吗?

考虑将结构数组替换为结构的每个成员的单独数组。

weights = rand(1, 1000);

如果你有一个结构成员是一个数组,你可以做一个额外的维度:

matrices = rand(3, 3, 1000);

如果你只是想保持整洁,你可以将这些数组放入一个结构体中:

edges.weights = weights;
edges.matrices = matrices;

但如果你需要保留一个结构数组,我认为你可以这样做

[edges.weight] = rand(1, 1000);

【讨论】:

两者都是一样的。但是,我认为我需要它是结构数组(意思是数组的对象)而不是数组结构(大型数组的单个大结构)。 MATLAB中两者有什么区别,有吗?含义 w.r.t 内存分配,如果是,它的含义是什么? 不同之处在于,在 Matlab 中,结构数组(“结构组织”)效率极低,因为每个结构都将其每个字段存储在单独的数组中,因此您不能进行向量化操作在他们。像 Brian 的数组结构(“平面组织”)会将其每个字段存储在原始数组中,这些数组在内存中是连续的,并且矢量化(快速)Matlab 函数将起作用。对于 Matlab 来说,这是一个更好的结构,而且更惯用。【参考方案5】:

示例中的结构未正确初始化的原因是您使用的语法仅处理结构数组中的最后一个元素。对于一个不存在的数组,其余的将被隐式填充为在所有字段中具有默认值 [] 的结构。

为了清楚地说明这种行为,请尝试使用clear edges; edges(1:3) = struct('weight',1.0) 做一个短数组,并查看edges(1)edges(2)edges(3) 中的每一个。 edges(3) 元素的权重为 1.0,如您所愿;其他人有[]

高效初始化结构数组的语法就是其中之一。

% Using repmat and full assignment
edges = repmat(struct('weight', 1.0), [1 1000]);

% Using indexing
% NOTE: Only correct if variable is uninitialized!!!
edges(1:1000) = struct('weight', 1.0);  % QUESTIONABLE

当索引到未初始化的边数组时,注意1:1000 而不是1000

edges(1:1000) 表单存在问题:如果 edges 已初始化,则此语法只会更新所选元素的值。如果边的元素超过 1000 个,则其他元素将保持不变,并且您的代码将出现错误。或者,如果 edges 是不同的类型,您可能会收到错误或奇怪的行为,具体取决于其现有数据类型。为了安全起见,您需要在使用索引语法进行初始化之前执行clear edges。因此,最好使用repmat 表单进行完整分配。

但是:无论您如何初始化它,对于较大的数据集,像这样的结构数组总是天生就很慢。您不能对其进行真正的“矢量化”操作,因为您的原始数组都被分解为每个结构元素内的单独 mxArrays。这包括您问题中的字段分配 - 无法对其进行矢量化。相反,您应该像 Brian L 的回答所建议的那样切换数组结构。

【讨论】:

【参考方案6】:

您可以使用反向结构,然后执行所有操作而不会出现任何错误 像这样

x.E(1)=1;
x.E(2)=3;
x.E(2)=8;
x.E(3)=5;

然后进行如下操作

x.E

ans =

    3     8     5

或者像这样

x.E(1:2)=2

x = 

    E: [2 2 5]

或者这个

x.E(1:3)=[2,3,4]*5

x = 

    E: [10 15 20]

它确实比 for_loop 快,而且你不需要其他大函数来减慢你的程序。

【讨论】:

以上是关于结构的Matlab数组:快速分配的主要内容,如果未能解决你的问题,请参考以下文章

Matlab分配3D数组的1D切片

MATLAB 结构体数组赋值

在MATLAB中直接将大数组写入磁盘时,是不是需要预先分配?

使用 MATLAB mex 将向量与另一个向量分配时出现分段错误

如何在 Matlab 中将字符数组的偶数和奇数索引重新分配到一个新的较小字符数组中?

从 for 循环 matlab 内部生成的变量分配向量值