2013-04-02 5 views
-1

Вот подпрограмма, которую я пытаюсь оптимизировать. Он использует ссылки на массивы по большей части. В настоящее время эта подпрограмма занимает ок. 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]; 
} 

Каждый шаг расчета и числа хрустания необходим. Он компилируется, но вы не сможете правильно использовать подпрограмму, если у вас нет файла данных.

+0

Код? Трудно ответить на этот вопрос без кода. – andersoj

+1

Почему вы отредактировали вопрос, чтобы полностью удалить код? Возможность взглянуть на исходный код - важная часть того, чтобы увидеть ценность рекомендованных оптимизаций. –

ответ

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 найти действительное узкое (ы) и целевые оптимизации в этих точках.

+1

хороший! спасибо, что привело к сокращению времени работы ок. 5- 12 секунд. :-) Есть ли что-нибудь еще, что вы видите? – cooldood3490

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] 
} 

Даже после оптимизации Дэйва 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 
    ... 
} 
+0

@steveni благодарит за предложение! Я попробую это. вы можете удалить подпрограмму, которую вы указали выше? он еще не готов к открытому исходному состоянию: 0 – cooldood3490

+0

сделано. дайте мне знать, что вы получаете после этого. – stevenl

+0

Большое спасибо. Сделаю! Я осуществлю это позже, а затем вернусь к вам. – cooldood3490

Смежные вопросы