如何使用PDL创建序列?

4

我正在尝试使用PDL将我的R代码的一部分转换成Perl,并且我想知道除了平凡的my $xx=pdl(1..20)之外,PDL是否有任何语法用于创建序列。

例如,像将向量['a','b']重复20次 => a,b,a,b,a,b.... 20次? [编辑]: 基本重复可以使用正常的Perl repeat string x 运算符完成,但我正在寻找类似于R中的rep()和seq()的函数:

[R]
> rep(1:3, each=2, times=3)
1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3
> rep(1:4, c(1,2,3,2))
1 2 2 3 3 3 4 4
> seq(0,12,3)
0 3 6 9 12
5个回答

3

嗯,我刚开始使用PDL,但从我所见和使用的情况来看,它似乎并不是你想要用来制作序列的最佳选择。你最好使用Perl的范围运算符(..)与任何组合的mapgrepx

话虽如此,如果你确实有某种原因坚持要使用PDL,你可能可以使用sequence函数,然后调整piddle,直到它看起来像你想要的东西:

pdl> p sequence(10)

[0 1 2 3 4 5 6 7 8 9]


pdl> p sequence(2,4) #Slice column 1 for evens, 2 for odds.

[
 [0 1]
 [2 3]
 [4 5]
 [6 7]
]


pdl> p sequence(3,4) * 5 #Multiply to step by an amount.

[
 [ 0  5 10]
 [15 20 25]
 [30 35 40]
 [45 50 55]
]

您还可以使用切片来抓取列以沿着序列进行步进。
对于其他任何内容,例如您在R示例中所做的事情,您需要开始变得有创意:
pdl> p $a = (yvals zeroes(2,3))+1

[
 [1 1]
 [2 2]
 [3 3]
]

pdl> p pdl($a,$a,$a)->flat #-> rep(1:3, each=2, times=3)
[1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3]

如果我知道如何更轻松地复制矩阵,则上述内容将更短

[编辑] 看起来使用dummy就可以轻松完成!

$a = (zeroes(2,3)->yvals + 1)->dummy(2,3)->flat

再次强调,除非您有特定需要,否则最好使用perl来生成序列。

[编辑] 下面是如何做到这一点:

请注意,'x'不仅是字符串乘法器,它还可以乘以列表。您需要明确地在变量周围使用括号,以通知perl正在对列表使用'x'。

#> rep(1:3, each=2, times=3)
my @s = map {($_) x 2} (1..3) x 3;

#> seq(0,12,3)
my @s = map {$_ * 3} 0..12/3;

#> rep(1:4, c(1,2,3,2))
#Ewww. So you basically want to multiply one list by another list.
#Here's one way to do it:
use List::MoreUtils qw(pairwise);
my @s = &pairwise(sub {($a) x $b}, [1..4], [1,2,3,2])

+1,感谢您提供的最近三个示例。最后一个是一个不错的技巧。 - Pablo Marin-Garcia
没问题。是的,最后一个技巧略微高级一点。如果pairwise不强制你给它数组(这就是为什么我需要使用'&'符号并用括号括起来的原因),它会更好地运行。 - Jarrod Funnell

3
我不了解任何特定于 PDL 的语法,但是使用 Perl,您可以使用 x 运算符来重复列表中的元素。也许
$xx = pdl(  ('a','b') x 20   );

可以工作。


1
+1 给你,-1 给我,因为这不是一个好的例子 ;-)。'x $times' 填充了明显的 Perl 解决方案的一部分(如“..”)。我正在寻找类似于 R 中的 seq() 和 rep() 的东西。请参见我的编辑后的问题。 - Pablo Marin-Garcia

3
PDL没有seq()rep()这两个函数,但它拥有构造函数和能够操作、重组多维数据的能力。具体来说,可以通过在原始数据中添加那些大小的虚拟维度,然后将结果重组为1-D来复制序列。使用sequence()构造函数可以生成带有start:stop:stride的序列,该序列是由一系列整数上的算术运算生成的。以下是一些PDL版本,它们对应于原始问题中的两个R代码片段,并附有注释以说明对应关系:
pdl> pdl(1..3)                  # 1:3
$PDL1 = [1 2 3];

pdl> pdl(1..3)->(*2)->flat      # rep(1:3, each=2)
$PDL1 = [1 1 2 2 3 3];

pdl> pdl(1..3)->(,*3)->flat     # rep(1:3, times=3)
$PDL1 = [1 2 3 1 2 3 1 2 3];

pdl> pdl(1..3)->(*2,,*3)->flat  # rep(1:3, each=2, times=3)
$PDL1 = [1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3];

pdl> rld(pdl(2,1,5),pdl(1..3))  # rep(1:3, c(2,1,5))
$PDL1 = [1 1 2 3 3 3 3 3];


pdl> sequence(13)->(0:12:3)     # seq(0,12,3)
$PDL1 = [0 3 6 9 12];

注意使用rld,运行长度解码命令以执行向量rep操作。使用这种类型的索引和维度操作实现R例程是很简单的。此外,以上大多数使用整数索引操作。如果您需要支持浮点数,您需要做一些其他的事情。
请参阅PDL::Basic获取序列内容并查看PDL::Slices获取索引操作(PDL::NiceSlice也相关,因为上面使用了该语法)。可以轻松尝试使用PDL shells之一:perldlpdl2来进行操作。
PDL网站位于http://pdl.perl.org。有关PDL的更多讨论,请使用perldl邮件列表以获得广大PDL社区更快的响应。

1

正如其他人所说,使用Perl并将其传递给pdl构造函数可能更容易完成一些示例。然而,最后一个示例足够简单:

$x = 3*xvals(5);
print $x; # [0 3 6 9 12]

经过一番努力,尽管我不懂R语言,但我还是想知道这个问题是否表述清楚。我开始假设某个新的pdl_rep函数的输入将是一个基础piddle和一些重复规范。然而,当基础piddle的维度高于简单向量时,我开始怀疑自己应该如何处理。因此,我只考虑了1D输入。然后我意识到,正如我和其他人所说的那样,要执行ceach类型的操作,必须在Perl级别上分解基础piddle并操作元素,然后重建一个piddle,否则就要进行一些愚蠢的维度操作。所有这些的结果是,似乎构建这样一个函数最简单的方法是让它成为一个pdl构造器。
一旦得出这个结论,我意识到,确实从良好构造的映射操作中构建您的piddle是您的意图。PDL旨在从Perl的强大功能中受益,否则它将成为一种独立的语言。设计师可能没有实现这个rep函数,因为Perl已经拥有了它的优势。
可能太长了,但我认为您的简短答案是让您的PDL也受益于Perl!

谢谢Joel +1,我正在探索PDL对我的需求有多好,它将节省我创建动态R代码和在perl中写入数据的时间,同时编写两个文件和qx("R CMD my_script.R")。你说得对,这些seq和rep函数可能可以在普通的perl中完成。那么我的问题是:是否有任何per模块专门用于执行此操作(因此我不需要使用这些典型函数重新发明轮子)?我认为由于PDL的利基市场,它有很大的机会拥有这些工具。 - Pablo Marin-Garcia
我不知道有任何的,我最近才开始使用PDL::Util模块(也可以参见github),一旦编写完成,这将是一个很好的存放位置。 - Joel Berger
@PabloMarin-Garcia,你可以看一下List::MoreUtils(特别是mesh),List::GenList::Maker这些高级列表帮助。 - Joel Berger

1

以下是关于sequence()函数和矩阵的一些有趣信息。

$x = sequence(20)*2+1; ##odd
[1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39]
$x = sequence(20)*2;  ##even 
[0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38]
$x = sequence(20)%2; ## binary pattern
[0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]
$x = sequence(20)%10  ## position matrix
[0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9]
$x = sequence(20)<=>10;  ## ray matrix
[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 1 1 1 1 1 1 1 1 1]
$x = sequence(20)%4+2;  ## repeating pattern
[2 3 4 5 2 3 4 5 2 3 4 5 2 3 4 5 2 3 4 5]
$x = sequence(20)%6;  ##  notice how this is different 
[0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1]

在编程中,将3D像素转换为TriD序列更快且使用的资源更少。 - Mark Baker

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