Matlab中类似于R中rep函数的函数

21

我正在寻找一个在Matlab中与R中的rep函数类似的函数。例如,使用rep,我可以执行以下操作:

> rep(c(1,2,3),times=3)
[1] 1 2 3 1 2 3 1 2 3

> rep(c(1,2,3),each=3)
[1] 1 1 1 2 2 2 3 3 3
> 

在Matlab中有一个repmat函数,它可以完成第一部分

>> repmat([1,2,3],1,3)

ans =

     1     2     3     1     2     3     1     2     3
但第二部分我不知道如何做到(或者至少我想不出来如何做到)。
有什么建议吗?

简直不敢相信我之前不知道 rep 函数有 each 选项;这段时间一直在用一个 hacky 的 one-liner... - bnaul
请注意,自Matlab 2015a以来,现在有一个内置函数可以完全做到这一点:repelem - Dan
4个回答

12

您可以通过首先定义一个函数来相当精确地复制R中rep函数的语法, 例如:

function [result]=rep(array, count)
matrix = repmat(array, count,1);
result = matrix(:);

然后,您可以通过使用行向量或列向量中的任一一个来复现所需的行为:

>> rep([1 2 3],3)
ans =
 1     1     1     2     2     2     3     3     3

>> rep([1 2 3]',3)
ans =
 1     2     3     1     2     3     1     2     3

请注意,我在第二个调用中使用了转置(')运算符,将输入数组作为列向量传递(即3x1矩阵)。

我在我的笔记本电脑上对此进行了基准测试,对于一个包含100,000个元素的基础数组,重复100次,与使用上面的ceil选项相比,它的速度提高了2到8倍,具体取决于您是想要第一种还是第二种排列方式。


快速而简单!我很惊讶repmat是赢家,但在这种情况下它绝对似乎是最好的解决方案! - Dan
如果实现得当,repmat应该非常快,因为它通过从一个位置复制内存来执行重复。具有大量缓存的现代处理器在这方面表现相当不错。这也是两种用法之间速度差异达到4倍的原因:快速的用法具有步幅为1的内存访问,而另一种用法具有步幅长度(数组)的内存访问,这些访问速度较慢。 - bcumming

8

很好的问题 +1。通过Kronecker张量积,可以使用整洁的单行方法来完成此操作,例如:

A = [1 2 3];
N = 3;
B = kron(A, ones(1, N));

然后:

B =

     1     1     1     2     2     2     3     3     3
更新:@Dan提供了一种非常简洁的解决方案,看起来比我使用的kron方法更有效,所以在离开页面之前请查看那个答案:-) 更新:@bcumming也提供了一个很好的解决方案,当输入向量很大时应该能很好地扩展。

我试图提出一个我能理解的解决方案,因为我不知道Kronecker张量积是什么。你可能对结果感兴趣,我认为它比kron()函数更快,尽管我还没有进行适当的基准测试... - Dan

6

如果像我一样,您不知道什么是Kronecker张量积,那么您可能会对这个更直观的解决方案感兴趣(实际上,我认为它更快):

c(ceil((1:length(c)*n)/n));

在这里,我使用向量索引来复制矩阵。例如,在上面的两个案例中,我们可以这样做:

c = 1:3;
c([1 1 1 2 2 2 3 3 3]) %for each
c([1 2 3 1 2 3 1 2 3]) %for times

所以问题是,如果没有你所要求的功能,我们如何创建一个向量[1 2 3 1 2 3 1 2 3]。因此,我创建了一个具有所需元素数量的向量,即1:9,然后将其除以三并向上取整(即在命令行中尝试ceil((1:9)/3))。
一些基准测试(我知道这些东西应该在循环中完成,因此可能不太准确):
c = 1:3; n = 3;
tic; k = kron(c, ones(1, n)); toc; % 0.000208 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.000025 seconds.
clear;
c = 1:1000000; n = 3;
tic; k = kron(c, ones(1, n)); toc; % 0.143747 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.090956 seconds.
clear;
c = 1:10000; n = 1000;
tic; k = kron(c, ones(1, n)); toc; % 0.583336 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.237878 seconds.

1
非常整齊 +1!我在我的機器上驗證了你的速度測試,加了一些循環,得到的結果相當代表性。通常情況下,我發現你的方法比 kron 快大約4倍。但更直觀嗎?我覺得這取決於觀察者的眼光 :-) 克羅內克乘積在概念上非常簡單,只要經過初步的學習成本就行了... - Colin T Bowers
是的,说得也对 - 我猜只是名字的问题,因为它里面有“张量”这个词,所以吓到了我 :) - Dan
它在我的小例子中确实有效,但我想要适用于“不规则”向量的东西。例如,像c = [1.34,9.2,-8.2,99]这样的向量。 - user2005253
1
它适用于任何向量,甚至文本。它肯定适用于您评论中的向量。它甚至可以处理这个:n=3; c = 'wowee!'; c(ceil((1:length(c)*n)/n)) - Dan

1

Here's one idea:

a=[1,2,3];
reshape(repmat(a,1,length(a)),1,length(a)^2)

ans =

 1     2     3     1     2     3     1     2     3

reshape(repmat(a,length(a),1),1,length(a)^2)

ans =

 1     1     1     2     2     2     3     3     3

我目前还没有找到一个能够一步完成这个操作的更简单的函数,但如果有的话,我很感兴趣。


1
有一个更简单的一步函数:kron(Kronecker张量积)。我已经添加了一个带有示例的答案。干杯。 - Colin T Bowers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接