我有一个一维 PDL,我想对它的每一半进行计算;即拆分它,然后在前半部分进行计算,在后半部分进行相同的计算。
有没有一种更简单/更好/优雅的方法来简单地将 PDL 分成两半,而不是获取元素的数量(使用 nelem),将其分成两部分,然后做两块切片?
谢谢
是的,只要你不需要直接调用 slice 来获得你想要的东西。你可以用这样的东西链接splitdim
和dog
:
# Assume we have $data, a piddle
my ($left, $right) = $data->splitdim(0, $data->nelem/2)->dog;
当然,这很容易扩展到两个以上的部门。但是,如果您想将其扩展到更高维的 piddle(即所有存储在一个 piddle 中的时间序列的集合),您需要更微妙一些。如果您想沿第一个维度(索引为 0)进行拆分,您可以这样说:
# Assume we have $data, a piddle
my ($left, $right) = $data->splitdim(0, $data->dim(0)/2)->mv(1, -1)->dog;
该splitdim
操作将第 0 维拆分为两个维度,第 0 维的长度为 dim(0)/2,第 1 维的长度为 2(因为我们将其分为两部分)。由于dog
在最后一个维度上进行操作,因此我们在调用之前将第一个维度移动到末尾dog
。
然而,即使使用一维解决方案,也有一个警告。由于其$data->splitdim
工作方式,如果您有奇数个元素,它将截断最后一条数据。在一个有 21 个元素的 piddle 上尝试这个操作,你就会明白我的意思:
my $data = sequence(20);
say "data is $data"; # lists 0-19
my ($left, $right) = $data->splitdim(0, $data->nelem/2)->dog;
say "left is $left and right is $right"; # lists 0-9, then 10-19
$data = sequence(21);
say "data is $data"; # lists 0-20, i.e. 21 elements
my ($left, $right) = $data->splitdim(0, $data->nelem/2)->dog;
say "left is $left and right is $right"; # lists 0-9, then 10-19!!
如果您想避免这种情况,您可以生成自己的方法,将第一个维度分成两半而不截断。它可能看起来像这样:
sub PDL::split_in_half {
my $self = shift;
# the int() isn't strictly necessary, but should make things a
# tad faster
my $left = $self->slice(':' . int($self->dim(0)/2-1) );
my $right = $self->slice(int($self->dim(0)/2) . ':');
return ($left, $right);
}
在这里,我还使用了int
内置来确保我们没有.5
ifdim(0)
是奇数。它有点复杂,但是我们将这种复杂性精确地埋入了一种方法中,因此我们不必考虑复杂性,因此我们不妨在使用它的同时为自己购买几个时钟周期。
然后您可以轻松地调用该方法:
my ($left, $right) = $data->split_in_half;