Matlab 向量的重复元素

Matlab 向量的重复元素,matlab,vector,repeat,run-length-encoding,Matlab,Vector,Repeat,Run Length Encoding,我有一个值向量a,包含元素I,例如: A=[0.10.20.30.40.5] 然后说r=[5231] 现在,我想重新创建一个新的向量,它包含a中I值的重复r(I),这样新中的第一个r(1)=5个项具有值a(1),新向量的长度是sum(r)。因此: 重新=[0.10.10.10.1 0.1 0.1 0.2 0.2 0.3 0.3 0.4 0.4 0.5] 我确信这可以通过精心设计的for-循环组合来实现,例如repmat,但有人知道如何以更平滑的方式实现吗?据我所知,在MATLAB中没有等效的函数

我有一个值向量
a
,包含元素
I
,例如:

A=[0.10.20.30.40.5]
然后说
r=[5231]

现在,我想重新创建一个新的向量
,它包含
a
I
值的重复
r(I)
,这样新
中的第一个
r(1)=5个
项具有值
a(1)
,新向量的长度是
sum(r)
。因此:

重新=[0.10.10.10.1 0.1 0.1 0.2 0.2 0.3 0.3 0.4 0.4 0.5]


我确信这可以通过精心设计的
for
-循环组合来实现,例如
repmat
,但有人知道如何以更平滑的方式实现吗?

据我所知,在MATLAB中没有等效的函数来实现,尽管
R
可以为您实现这一点。。。。太嫉妒了

在任何情况下,我建议的唯一方法是按照您的建议,使用
repmat
运行
for
循环。但是,如果您想将此作为一行程序来执行,您可能可以这样做。。。从技术上讲,需要两个步骤来完成后处理,才能将其转化为一个向量。因此,您可以尝试以下方法:

Anew = arrayfun(@(x) repmat(A(x), r(x), 1), 1:numel(A), 'uni', 0);
Anew = vertcat(Anew{:});
这实质上是用较少的代码对复制向量进行
循环和串联。我们遍历
A
r
中的每对值,并吐出复制向量。它们中的每一个都将在一个单元数组中,这就是为什么需要将它们全部放入一个向量中

我们得到:

Anew =

    0.1000
    0.1000
    0.1000
    0.1000
    0.1000
    0.2000
    0.2000
    0.3000
    0.3000
    0.3000
    0.4000
    0.4000
    0.5000
请注意,其他人也尝试过类似于您在本文中所做的事情:。这实际上是模仿
R
rep
方式,这就是您想要做的


备选方案-对
循环使用

由于@Divakar的基准测试,我很好奇如何预先分配数组,然后使用实际的
for
循环来迭代
A
r
,并通过索引来填充它。因此,使用
进行
循环和索引的上述等效代码为:

Anew = zeros(sum(r), 1);
counter = 1;
for idx = 1 : numel(r)
    Anew(counter : counter + r(idx) - 1) = A(idx);
    counter = counter + r(idx);
end
我们需要一个变量来跟踪需要在数组中插入元素的位置,该变量存储在
计数器中。我们用每个数字要复制的元素总数来抵消这一点,这些元素存储在
r
的每个值中

因此,此方法完全避免使用
repmat
,而只是使用索引来生成复制向量


基准测试(Divakar) 在Divakar的基准测试代码的基础上,我实际上尝试在我的机器上运行所有测试,除了
for
循环方法。我只是在相同的测试用例中使用了他的基准测试代码

以下是我根据算法得到的计时结果:

案例1-
N=4000
max\u repeat=4000
案例2-
N=10000
max\u repeat=1000
在这些情况下,
cumsum
实际上击败了
arrayfun
。。。这是我最初的期望
bsxfun
击败了所有人,除了
for
循环。我的猜测是,由于我和Divakar在
arrayfun
中的时间不同,我们在不同的体系结构上运行代码。我目前正在Mac OS X 10.9.5 MacBook Pro机器上使用MATLAB R2013a运行测试


正如我们所看到的,
for
循环要快得多。我知道一个事实,当涉及到
for
循环中的索引操作时,JIT会起作用并提供更好的性能。

首先考虑形成一个索引向量
[1 1 1 2 3 3 4 4 5]
。注意到这里的规则增量让我想到了cumsum:我们可以通过将一个放在零向量的正确位置来获得这些步骤:
[1 0 0 0 1 0 1 0 1 1]
。我们可以在输入列表上运行另一个
cumsum
。调整结束条件和基于1的索引后,我们得到以下结果:

B(cumsum(r) + 1) = 1;
idx = cumsum(B) + 1;
idx(end) = [];
A(idx)

基于bsxfun的方法-

A = [0.1 0.2 0.3 0.4 0.5]
r = [5 2 3 2 1]

repeats = bsxfun(@le,[1:max(r)]',r) %//' logical 2D array with ones in each column 
                                    %// same as the repeats for each entry
A1 = A(ones(1,max(r)),:) %// 2D matrix of all entries repeated maximum r times
                         %// and this resembles your repmat 
out = A1(repeats) %// desired output with repeated entries
它基本上可以变成一艘两艘班轮-

A1 = A(ones(1,max(r)),:);
out = A1(bsxfun(@le,[1:max(r)]',r));
输出-

out =
    0.1000
    0.1000
    0.1000
    0.1000
    0.1000
    0.2000
    0.2000
    0.3000
    0.3000
    0.3000
    0.4000
    0.4000
    0.5000

标杆管理 到目前为止,可以为这里介绍的解决方案生成一些基准结果

基准测试代码-案例I

%// Parameters and input data
N = 4000;
max_repeat = 4000;
A = rand(1,N);
r = randi(max_repeat,1,N);
num_runs = 10; %// no. of times each solution is repeated for better benchmarking

disp('-------------------  With arrayfun')
tic
for k1 = 1:num_runs
    Anew = arrayfun(@(x) repmat(A(x), r(x), 1), 1:numel(A), 'uni', 0);
    Anew = vertcat(Anew{:});
end
toc, clear Anew

disp('-------------------  With cumsum')
tic
for k1 = 1:num_runs
    B(cumsum(r) + 1) = 1;
    idx = cumsum(B) + 1;
    idx(end) = [];
    out1 = A(idx);
end
toc,clear B idx out1

disp('-------------------  With bsxfun')
tic
for k1 = 1:num_runs
    A1 = A(ones(1,max(r)),:);
    out2 = A1(bsxfun(@le,[1:max(r)]',r));
end
toc
结果

-------------------  With arrayfun
Elapsed time is 2.198521 seconds.
-------------------  With cumsum
Elapsed time is 5.360725 seconds.
-------------------  With bsxfun
Elapsed time is 2.896414 seconds.
-------------------  With arrayfun
Elapsed time is 2.641980 seconds.
-------------------  With cumsum
Elapsed time is 3.426921 seconds.
-------------------  With bsxfun
Elapsed time is 1.858007 seconds.
基准测试代码-案例二[数据量较大,但r的最大值较小]

%// Parameters and input data
N = 10000;
max_repeat = 1000;
结果

-------------------  With arrayfun
Elapsed time is 2.198521 seconds.
-------------------  With cumsum
Elapsed time is 5.360725 seconds.
-------------------  With bsxfun
Elapsed time is 2.896414 seconds.
-------------------  With arrayfun
Elapsed time is 2.641980 seconds.
-------------------  With cumsum
Elapsed time is 3.426921 seconds.
-------------------  With bsxfun
Elapsed time is 1.858007 seconds.
基准得出的结论
对于
案例一
阵列风
似乎是一条出路,而对于
案例二
bsxfun
可能是首选武器。因此,您正在处理的数据类型似乎决定了使用哪种方法。

+1为了快速、准确地实现,您可以将其转换为一行:
cell2mat(arrayfun(@(n)repmat(a(n),[1 r(n)]),1:numel(r),'uniformoutput',0))
如果我有一些繁重的工作,我会把它发送给您的!;)啊,我是说责任吗!!?:D@Divakar-哈哈,这是我至少能做的:)你已经帮了我很多忙了。我的MacBook上的GPU没有我家里的机器强大。。。。但那个只有8GB的内存。可能是时候升级了。感谢所有非常有用的建议和基准测试,我想我会选择
for
循环,但我确实需要了解我的RAM,尽管16GB必须足够了!:)这一定很快+1像往常一样做好基准测试工作!我投你一票already@LuisMendo谢谢我并不是真的在为bsxfun担保,但是哇!实际上,我认为带有二进制相关函数句柄的
bsxfun
非常便宜。也忘了给你投票了+1.基准测试方面的出色工作。在选择使用哪种方法之前,您必须了解
r
的结构,这很酷。