-1

これが私が最適化しようとしているサブルーチンです。ほとんどの場合、配列参照を利用します。現在、このサブルーチンには約 10 分かかります。平均して実行するのに 30 ~ 40 秒。可能であれば、これを 10 秒に短縮したいと考えています。不要なものが飛び出しますか?

sub compute{
    # takes two params: 2 array_refs
    my ($gene_exp_ref, $centroids_ref) = @_;
    my ($numerator, $denominator) = 0;

    my ($prod_ref, $diff_x_ref, $diff_y_ref, $x_sq_ref, $y_sq_ref) = [];  # diff_y is the center_gene
    my %gene_center_pcc;                   # diff_x is gene of interest

    my $gene_exp_average = mean($gene_exp_ref);

    for my $gene_exp (@{$gene_exp_ref}) {
        push(@{ $diff_x_ref }, ($gene_exp - $gene_exp_average));
    }

    # possible bottleneck
    for my $centroid_gene_exp_ref (values %{$centroids_ref}){
        $diff_y_ref = [];  # initilize back to empty array
        for my $index (@{$centroid_gene_exp_ref}) {
            push(@{ $diff_y_ref }, ($index - mean($centroid_gene_exp_ref)));
        }

        @{ $prod_ref } = map { @{ $diff_x_ref }[$_] * @{ $diff_y_ref }[$_] } 0..$#{ $diff_x_ref };

        $numerator = sum($prod_ref);

        @{ $x_sq_ref } = map {$_*$_}@$diff_x_ref;
        @{ $y_sq_ref } = map {$_*$_}@$diff_y_ref;

        $denominator = sqrt(sum($x_sq_ref)) * sqrt(sum($y_sq_ref));

        my $r = $numerator/$denominator;

        my ($center) = grep { @{$gene_centers{$_}} ~~ @$centroid_gene_exp_ref } keys %gene_centers;
        $gene_center_pcc{$center} = $r;
    }

#return the center with the highest PCC
return (sort {$gene_center_pcc{$b} <=> $gene_center_pcc{$a}}
    keys %gene_center_pcc)[0];
}

それぞれの計算と数値計算のステップが必要です。コンパイルはできますが、データ ファイルがないとサブルーチンを適切に使用できません。

4

2 に答える 2

3
for my $index (@{$centroid_gene_exp_ref}) {
    push(@{ $diff_y_ref }, ($index - mean($centroid_gene_exp_ref)));
}

これにより、 内のすべてのアイテムの平均が再計算され@{$centroid_gene_exp_ref}ます。その配列が大きい場合、指数関数的に加算されます(mean()結果をキャッシュまたはメモ化せず、呼び出されるたびに配列をループすることを強制すると仮定しています)。平均を自分でキャッシュすることで、かなりの時間を節約できる場合があります。

my $mean = mean($centroid_gene_exp_ref);
for my $index (@{$centroid_gene_exp_ref}) {
    push(@{ $diff_y_ref }, ($index - $mean));
}

それを超えて、 Devel::NYTProfでチェックして、実際のボトルネックを見つけ、それらのポイントでの最適化を目標にします。

于 2013-04-02T05:44:03.573 に答える
2

compute()のすべてのキーを呼び出すことを示した以前の投稿を考慮して、全体像を見る必要があります%$centroids_ref

foreach my $key ( keys %HoA ) {
    compute($HoA{$key}, \%HoA);  # on the first iteration, this actually passes an aref to [1,3,3,3]
}

Dave Sherohman の最適化の後でも、まだ多くの計算 ( などmean) を何度も繰り返しています。

私の提案は、外側のループを に持ち込むことですcompute()。次に、HoA のキーごとに計算を保存し、それらの値をキーごとに再利用できます。

sub compute{
    my ($centroids_ref) = @_;

    # precalculate these values once
    my %means;
    my %diffs;
    my %sqrts;
    foreach my $key (keys %$centroids_ref) {
        my $mean = mean($centroids_ref->{$key});
        my @diffs = map {$_ - $mean} @{$centroids_ref->{$key}};

        my @squares = map {$_ * $_} @diffs;
        my $sqrt = sqrt(sum(\@squares));

        $means{$key} = $mean;
        $diffs{$key} = \@diffs;
        $sqrts{$key} = $sqrt;
    }

    # now do the main calculations from the 'possible bottlenecks' section
    ...
}
于 2013-04-02T07:45:33.093 に答える