首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对存储在哈希中的AoAs进行操作。PDL与无PDL

对存储在哈希中的AoAs进行操作。PDL与无PDL
EN

Stack Overflow用户
提问于 2011-06-19 12:30:36
回答 4查看 242关注 0票数 3

我有一个AoAs的哈希:

代码语言:javascript
复制
$hash{$key} = [ 
               [0.0,1.0,2.0],
               10.0,
               [1.5,9.5,5.5],
              ];

我需要按如下方式进行处理:

代码语言:javascript
复制
$err += (($hash{$key}[0][$_]-$hash{key}[2][$_])*$hash{$key}[1])**2 foreach (0 .. 2);

计算两个数组之间的平方加权差。由于我的散列很大,我希望PDL可以帮助加速计算,但由于某些原因,它没有。我仍然是PDL的新手,所以我可能把事情搞砸了。下面使用PDL的脚本速度大约慢10倍。描述:以下两个脚本是我试图简单地表示我的程序中正在发生的事情。我将一些参考值读入散列,然后将观察值(即时拉入散列)与这些值进行多次加权比较。在脚本中,我将引用数组、权重和观察数组设置为一些任意的固定值,但在运行时情况并非如此。

下面是两个不带PDL和带PDL的简单脚本:

不使用PDL

代码语言:javascript
复制
use strict;
use warnings;
use Time::HiRes qw(time);

my $t1 = time;
my %hash;
my $error = 0;

foreach (0 .. 10000){
  $hash{$_} = [
               [0.000, 1.000, 2.0000],
               10.0,
               [1.5,9.5,5.5],
              ];
  foreach my $i (0 .. 2){
    $error += (($hash{$_}[0][$i]-$hash{$_}[2][$i])*$hash{$_}[1])**2;
  }
}

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1,$error);

使用PDL

代码语言:javascript
复制
use strict;
use warnings;
use PDL;
use Time::HiRes qw(time);

my $t1 = time;
my %hash;
my $error = 0;

foreach (0 .. 10000){
  $hash{$_}[0] = pdl[0.000, 1.000, 2.0000];
  $hash{$_}[1] = pdl[10.0];
  $hash{$_}[2] = pdl[1.5,9.5,5.5];
  my $e = ($hash{$_}[0]-$hash{$_}[2])*$hash{$_}[1];
  $error += inner($e,$e);
}

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1, $error);
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-06-19 12:48:42

首先,除非数组很大,否则PDL不会有太大帮助。因此,与其使用由0到10000索引的散列,每个散列(基本上)具有7个标量元素,您是否可以创建7个PDL向量,每个向量包含10001个元素,并使用向量操作对这些向量进行操作?

其次,每次命名表达式$hash{$_}时都会对其求值,因此应该将其提取出来。例如,在您的标准Perl代码中,您应该这样做:

代码语言:javascript
复制
my $vec = $hash{$_};
foreach my $i (0 .. 2){
    $error += (($vec->[0][$i]-$vec->[2][$i])*$vec->[1])**2;
}
票数 3
EN

Stack Overflow用户

发布于 2012-04-22 23:45:09

PDL经过优化,可以处理数组计算。您正在为您的数据使用散列,但由于键是数字,因此可以根据PDL数组对象对其进行重新制定,以获得性能上的巨大优势。下面的示例代码的所有PDL版本的运行速度比没有PDL代码的原始快大约36倍(比使用PDL代码的原始快300倍)。

所有PDL

代码语言:javascript
复制
use strict;
use warnings;
use PDL;
use Time::HiRes qw(time);

my $t1 = time;
my %hash;
my $error = 0;

my $pdl0 = zeros(3,10001);  # create a [3,10001] pdl
$pdl0 .= pdl[0.000, 1.000, 2.0000];

my $pdl1 = zeros(1,10001);  # create a [1,10001] pdl
$pdl1 .= pdl[10.0];

my $pdl2 = zeros(3,10001);  # create a [3,10001] pdl
$pdl2 .= pdl[1.5,9.5,5.5];

my $e = ($pdl0 - $pdl2)*$pdl1;
$error = sum($e*$e);

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1, $error);

有关使用PDL Book进行计算的详细介绍,请参阅PDL。PDL homepage也是所有PDL的一个很好的起点。

票数 5
EN

Stack Overflow用户

发布于 2011-06-19 16:31:53

我对您的代码进行了多次重构,首先将尽可能多的复杂性移到循环之外。其次,我删除了一层左右的抽象层。这大大简化了表达式,并在保持相同结果的情况下将我的系统上的运行时间减少了约60%。

代码语言:javascript
复制
use Modern::Perl;
use Time::HiRes qw(time);

my $t1 = time;
my $error = 0;

my @foo = ( 0.000, 1.000, 2.0000 );
my $bar = 10.0;
my @baz = ( 1.5, 9.5, 5.5 );

foreach ( 0 .. 10000 ) {
    $error += ( ( $foo[$_] - $baz[$_] ) * $bar )**2 for 0 .. 2
}

my $t2 = time;

printf ( "total time: %10.4f error: %10.4f\n", $t2-$t1,$error);

这只是普通的老式Perl;没有PDL。希望这对你的项目有帮助。

顺便说一句,在计算运行一段代码所需的时间时,我更喜欢Benchmark模块及其timethis()timethese()cmpthese()函数。你可以从中获得更多的信息。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6400553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档