向量化以下 for 循环
Vectorize the following for loop
i = [1 2 3 4 5];
a = {[1 3 4 5] [5 4 3] [1 2 3] [4] [5 2]};
b = {[1] [4 2 3] [1 3] [2 1 4] [1 2 3]};
对于a
和b
,以下条件成立
- 元胞数组
a
和b
的大小为i
a
和b
的每个数组中的每个元素都来自i
的元素
有什么方法可以向量化以下代码以避免for
循环
x = 0;
for elem = i
x = x + sum(ismember(cell2mat(a(a{elem})),b{elem}));
end
x
谢谢
方法 #1
在我看来,循环内的 cell2mat
会成为瓶颈。如果你 运行 它进行了相当多的循环迭代,就会感觉到这个瓶颈。因此,使用这个 post 我会尝试重新组织输入数组 a
以便在循环外使用 cell2mat
。这将用于提取所有元素,然后将单元格元素重新分组到另一个单元格数组中,其每个单元格将保存与原始代码每次迭代时提取的 cell2mat()
值相对应的值。因此,可以直接馈送这种重新组织的单元格阵列的每个单元格以替换 cell2mat(a(a{elem}))
.
因此,要实现所有这些承诺,实施方式为 -
% Re-organize a to create another cell array in which each cell
% would have "cell2mat(a(a{elem}))" for iterator elem
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
grouped_a = mat2cell(cell2mat(a(arr)),1,diff([0 grouped_cumlens]))
% Use grouped_a to perform the same operations but without cell2mat in loops
outx = 0;
for elem = i
outx = outx + sum(ismember(grouped_a{elem},b{elem}));
end
如果您迫切需要完全矢量化的代码,循环代码很容易用 bsxfun
进行矢量化,但我不确定这是否会提供性能优势,因为这取决于您拥有的数据格式输入。
方法 #2
这是从 a
中提取元素的另一种方法,它仍然适用于以前的版本。但是,它不是存储为另一个元胞数组,而是保留常规数组并另外保存与每次迭代时用于从中提取元素的限制相对应的开始和停止索引。因此,实现看起来像这样 -
% Code un-changed from the previous version
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
% Extract data into a regular array and decide start and stop indices
data = cell2mat(a(arr))
starts = [1 grouped_cumlens(1:end-1)+1]
stops = grouped_cumlens
% Use extracted data with its start,stop indices for each iteration
outx = 0;
for elem = i
outx = outx + sum(ismember(data(starts(elem):stops(elem)),b{elem}));
end
再次 bsxfun
可以与此版本一起使用以完全矢量化此处的内容!
i = [1 2 3 4 5];
a = {[1 3 4 5] [5 4 3] [1 2 3] [4] [5 2]};
b = {[1] [4 2 3] [1 3] [2 1 4] [1 2 3]};
对于a
和b
,以下条件成立
- 元胞数组
a
和b
的大小为i
a
和b
的每个数组中的每个元素都来自i
的元素
有什么方法可以向量化以下代码以避免for
循环
x = 0;
for elem = i
x = x + sum(ismember(cell2mat(a(a{elem})),b{elem}));
end
x
谢谢
方法 #1
在我看来,循环内的 cell2mat
会成为瓶颈。如果你 运行 它进行了相当多的循环迭代,就会感觉到这个瓶颈。因此,使用这个 post 我会尝试重新组织输入数组 a
以便在循环外使用 cell2mat
。这将用于提取所有元素,然后将单元格元素重新分组到另一个单元格数组中,其每个单元格将保存与原始代码每次迭代时提取的 cell2mat()
值相对应的值。因此,可以直接馈送这种重新组织的单元格阵列的每个单元格以替换 cell2mat(a(a{elem}))
.
因此,要实现所有这些承诺,实施方式为 -
% Re-organize a to create another cell array in which each cell
% would have "cell2mat(a(a{elem}))" for iterator elem
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
grouped_a = mat2cell(cell2mat(a(arr)),1,diff([0 grouped_cumlens]))
% Use grouped_a to perform the same operations but without cell2mat in loops
outx = 0;
for elem = i
outx = outx + sum(ismember(grouped_a{elem},b{elem}));
end
如果您迫切需要完全矢量化的代码,循环代码很容易用 bsxfun
进行矢量化,但我不确定这是否会提供性能优势,因为这取决于您拥有的数据格式输入。
方法 #2
这是从 a
中提取元素的另一种方法,它仍然适用于以前的版本。但是,它不是存储为另一个元胞数组,而是保留常规数组并另外保存与每次迭代时用于从中提取元素的限制相对应的开始和停止索引。因此,实现看起来像这样 -
% Code un-changed from the previous version
lens = cellfun('length',a)
arr = [a{:}]
cumlens = cumsum(lens(arr))
grouped_cumlens = cumlens(cumsum(lens))
% Extract data into a regular array and decide start and stop indices
data = cell2mat(a(arr))
starts = [1 grouped_cumlens(1:end-1)+1]
stops = grouped_cumlens
% Use extracted data with its start,stop indices for each iteration
outx = 0;
for elem = i
outx = outx + sum(ismember(data(starts(elem):stops(elem)),b{elem}));
end
再次 bsxfun
可以与此版本一起使用以完全矢量化此处的内容!