2012-12-19 9 views
5

Po wielkiej przerwie trwającej około 6 miesięcy wracam do świata Perla i Bioinformatyki, przechodząc pod innym naukowcem. Ale pierwsze zadanie nie przypomina tego, z jakimi miałem do czynienia po raz ostatni, więc póki poczyniłem pewne postępy, nie byłem w stanie poradzić sobie z tym problemem w całości. Próbuję też powtórzyć wszystko, czego nauczyłem się ostatnio, tak szybko, jak to możliwe, ponieważ zupełnie straciłem kontakt z programowaniem przez ostatnie 6 miesięcy. Zbiór danych wygląda następująco:Perl: Znajdź maksymalną wartość skrótu i ​​średnich obliczeniowych

NR_046018 DDX11L1  , 0 0 1 1 1 1 1 1 1 1 0 0 0 0 1.44 2.72 3.84 4.92 5.6 6.64 7.08 9.12 9.56 8.28 7.16 6.08 5.4 4.36 3.92 1.88 0 0 0.76 1 1 1 1.2 2 2 2 1.72 2 2 2 1.8 1 1.88 2.4 3 3.36 5 6 6 6.72 6.12 5.6 5.44 5.56 5 4.04 5 4.28 4 4 3.08 2.08 1.68 1.96 1.44 3 3.68 4 4.16 5 4.32 4.8 6.16 6 6.28 6.92 7.84 7 7.32 7.2 5.96 5 4.52 4.08 3 3 4.04 4.12 4.44 4 3.52 3.4 4 4 2.64 1.88 1 1 1 0.64 1 1 1.24 2 2.92 3 3 2.96 2 2 2.56 2 1.08 2.12 3 3 3 3 2.6 3 4.64 3.88 3.72 4 4 4.96 4.6 4 2.36 2 1.28 1 1 0.04 0 0.24 1.08 2.68 3.84 4.12 5.72 6 6 5.76 4.92 3.32 3.12 2.88 2.08 2 2 2 2 2 1.44 2.92 3.04 4.28 5.8 7.8 9.48 10.52 13.04 12.08 11.6 11.72 11 9.2 7.52 7.12 7.08 7.08 8.32 7 6.6 7.6 8.04 8.36 6.72 7.88 7.72 8.4 9.24 8.88 8.96 9.88 10.08 9.24 9.28 10.16 11.04 10.52 10 8.56 8 7.8 7.72 6.44 4.32 4 4 3.72 3.68 3.68 3.28 5.56 7.36 9.48 10 10.52 11 12.16 11.96 9.44 8.64 7.52 7 6.48 6 5 5.12 6.28 6 5.52 6 6.68 6.08 7.52 8.16 7.72 8.52 8.56 9.2 9.16 8.92 7.44 6 5 3.48 2.92 2.16 2 2 1.2 1 1 1 1.24 1.64 1 1 1.96 2 2 2 1.76 1 1 1 0.52 1.76 3.64 5.12 6 6 6 6 5.52 4.24 2.36 0.88 0 0 0.68 1 1 1 1 1 1 1 0.32 0 0 1 1 1.44 2.44 3.68 5.4 6.88 7 6 6.52 6.76 6.56 5.32 3.6 2.92 3 3.72 3.96 3.8 3 3 3 2.2 2.4 2.28 1.52 1 1 1 1.72 2 1.6 1 1 1 1 1 0.28 0.92 2 2 2.72 3.64 4 4.84 5 4.08 3 3 2.68 2.36 2 1.16 1 1 2 4.92 4.6 4 4 4 4 4.32 4 1.08 1 1.52 2 2 2 1.68 1 1 1.32 1.48 1 1 1.52 2 2 2 1.68 1 1 1.88 1.48 1 1 1 1 1 1 0.12 0.4 1 1 1.2 3.88 4 5 5 4.6 4 4 3.8 2.08 2 1 1 1.44 2.4 3 
NR_047520 LOC643837 , 3 2.2 0.2 0 0 0.28 1 1 1 1 2.2 4.8 5 5.32 5 5 5 5 3.8 1.2 1 0.4 0 0 0 0 0 1 1 1 1 1 1 1 1.56 1 1 1 1 1 1 1 0.44 0.68 1 1.52 3 3.6 4.96 6.8 9 8.32 8.72 8.48 7 7.4 8.8 7.92 7.12 8.84 8.56 9.4 10.2 10 7.24 6.44 6.76 6.16 5.72 4.96 4.8 5.16 6 5.84 4.12 3 3 2.64 2.56 3.08 3 4.16 5 6.72 7 7.16 7.44 5.76 5 4.56 4 3.68 5 5.4 5.52 6 6 5.28 5 3.6 2 2.08 1.48 1 2 2 2 2 2 1.36 1 1 0 0 0.68 1 1 1 1 1 1 1 0.32 0 0 0 1.16 2 2 2 2 2.88 3 3 1.84 1 2 2 2.04 2.12 2 2 2 2 1 1.28 1.96 1.36 2.76 3 3 3 3 2.72 2 1.64 0.76 1 1.36 2 2 2 2 2 1.48 1 0.64 0 0.08 1 1 1.08 2 2 2 2 2.68 2 2 2.16 3.4 4 4 4.2 4.24 4 5.68 6.52 4.6 4 4 3.8 3.8 4 3.12 2.24 2.6 3 4 4 3.2 3 2.2 2 1.4 1.84 1.24 2 2 2 2 2 2 1.16 0.76 0 0 0 0 0 0 0 0.36 1 1.68 2 2 2.92 5.4 6.76 7.64 7 6.88 7 7.36 7.92 6.24 5.92 7.04 9.52 11.52 12.88 14.8 16.36 19.88 22.24 20 19.36 16.92 15.24 13.84 10.88 8.24 5.08 4.96 3.12 3 2.88 2 2.8 2.96 4 4.44 5 6 6 6 5.12 3.28 2 1.56 1 0.08 1.68 2 2 2.84 3 3 3.8 3.92 2.32 2 2.2 2.16 2 2 1.2 1 1 1 0.8 0 0 0 0.72 2.88 3 3 3 3 3 3 2.28 0.12 0 0.52 1 1 1 1 1.44 2 2 1.48 1 1 1 1.56 1.56 1 1 1 1 1 1 0.44 0.8 1.48 3 3 3 3 3 3.56 3.2 2.76 2 2 2 2 2.68 2.44 2 1.76 1 1.4 2 2 1.56 2 2 2 2 2.04 2 2 1.76 1 1 1 1 0.56 0 0 0 0 0 0 0 0 0.72 1.52 2 2 2 2 2 2 1.28 0.48                    

1. Co jest potrzebne

  1. Dla każdego wiersza w pliku danych, znaleźć maksymalną wartość z zakresu numerów.
  2. Po znalezieniu maksimum dla wszystkich wierszy, znajdź średnie maksimum.

2. Strategia Myślałam

  1. oddzielić non część numeryczna z części non-numerycznym do "klucze" o hash.
  2. Umieść numeryczną część w "wartościach" skrótu.
  3. Przypisz „wartości” na tablicy @values
  4. użyć modułu use List::Util qw(max) znaleźć maksymalną wartość z tablicy
  5. przechowywania tych maksymalnych wartości w innej tablicy i znaleźć średnią z tej tablicy.

3. Kod napisany tak daleko

use warnings; 
use List::Util qw(max); 

#Input filename 
$file = 'test1.data'; 

#Open file 
open I, '<', $file or die; 

#Separate data into keys and values, based on ',' 
chop (%hash = map { split /\s*,\s*/,$_,2 } grep (!/^$/,<I>)); 
print "$_ => $hash{$_}\n" for keys %hash; #Code is working fine till here 

#Create a values array 
@values = values %hash; 
foreach $value(@values){ 
print "The values are : ", $value,"\n"; 
} 

4. Problem

Poza tym, nie jestem w stanie dowiedzieć się, jak dodać każdy "individual" tablicy element do nowa tablica, dzięki czemu mogę korzystać z funkcji max.

Co mam na myśli to, że na przykład first array element w @values zawiera dane takie jak 0 0 1 1 3 4.4. Model second array element może zawierać dane takie jak 3 2.2 0.28 1 1 4.8. Tak więc muszę umieścić each tych elementów tablicy w nowej tablicy, każdy element przechodząc w innej tablicy tak, że mogę być w stanie użyć funkcji max.

5. Punkty zauważyć,

  1. Większość wierszy zawiera 400 numerów, niektóre mają trochę mniej niż to, ale nie więcej niż 400.

  2. Istnieje w sumie 23 558 wierszy.

  3. Plik jest plikiem .txt, a wszystkie liczby w każdym wierszu są rozdzielane tabulatorami.

Byłbym wdzięczny każdemu, kto byłby na tyle uprzejmy, żeby wskazać mi w dobrym kierunku, czy może zapewnić lepszy kod do rozwiązania problemu, o którym mowa w 1.

+1

można również zapytać biostars: http://www.biostars.org/ – Pierre

+0

@Pierre Dziękujemy za naprowadzenie mnie na tej stronie. – Neal

+3

+1 za bardzo dobrze napisane pytanie i pokazanie pracy. – Axeman

Odpowiedz

7

Jeśli Rozumiem problem właściwie robisz to zbyt skomplikowane:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use List::Util qw(max); 

#Input filename 
my $file = 'test1.data'; 

#Open file 
open my $fh, '<', $file or die "Unable to open $file: $!\n"; 

my ($total, $num); 

while (<$fh>) { 
    my @values = split; 
    my $max = max(@values[3 .. $#values]); 
    $total += $max; 
    $num++; 
} 

my $average_max = $total/$num; 

Tylko jedno przejście nad plikiem, rozdzielenie linii do tablicy i karmienia wszystko z indeksu 3 do max. Dodaj $max do $total dla każdej linii, zwiększ licznik ($num) i obliczyć średnią wartość maksymalną z tego.

Powinieneś również zawsze używać use strict i leksykalnych uchwytów plików.

+0

Och, wow, proszę pana! Dziękuję bardzo! Po przyjrzeniu się twojemu rozwiązaniu zobaczyłem, jak bardzo skomplikowałem to, co robiłem! : | Muszę się jeszcze wiele nauczyć ... – Neal

+2

I tak, proszę pana, od tej pory zawsze będę używał 'use strict' i leksykalnych uchwytów plików. – Neal

1

Oto zabawne rozwiązanie. Jeśli używasz List::Util, równie dobrze możesz używać także sum.

#!usr/bin/perl 
use strict; 
use warnings; 
use List::Util qw/max sum/; 

my %line_max = map { 
    /([\w\s]*?)\s*,\s*(.*)/ or die "bad line"; 
    $1 => max split ' ', $2 
} <DATA>; 

print "$_: $line_max{$_}\n" foreach (keys %line_max); 

my $avg_max = sum (values %line_max)/scalar (values %line_max); 
print "average: $avg_max\n"; 

__DATA__ 
NR_046018 DDX11L1  , 0 0 1 1 1 1 1 1 1 1 0 0 0 0 1.44 2.72 3.84 4.92 5.6 6.64 7.08 9.12 9.56 8.28 7.16 6.08 5.4 4.36 3.92 1.88 0 0 0.76 1 1 1 1.2 2 2 2 1.72 2 2 2 1.8 1 1.88 2.4 3 3.36 5 6 6 6.72 6.12 5.6 5.44 5.56 5 4.04 5 4.28 4 4 3.08 2.08 1.68 1.96 1.44 3 3.68 4 4.16 5 4.32 4.8 6.16 6 6.28 6.92 7.84 7 7.32 7.2 5.96 5 4.52 4.08 3 3 4.04 4.12 4.44 4 3.52 3.4 4 4 2.64 1.88 1 1 1 0.64 1 1 1.24 2 2.92 3 3 2.96 2 2 2.56 2 1.08 2.12 3 3 3 3 2.6 3 4.64 3.88 3.72 4 4 4.96 4.6 4 2.36 2 1.28 1 1 0.04 0 0.24 1.08 2.68 3.84 4.12 5.72 6 6 5.76 4.92 3.32 3.12 2.88 2.08 2 2 2 2 2 1.44 2.92 3.04 4.28 5.8 7.8 9.48 10.52 13.04 12.08 11.6 11.72 11 9.2 7.52 7.12 7.08 7.08 8.32 7 6.6 7.6 8.04 8.36 6.72 7.88 7.72 8.4 9.24 8.88 8.96 9.88 10.08 9.24 9.28 10.16 11.04 10.52 10 8.56 8 7.8 7.72 6.44 4.32 4 4 3.72 3.68 3.68 3.28 5.56 7.36 9.48 10 10.52 11 12.16 11.96 9.44 8.64 7.52 7 6.48 6 5 5.12 6.28 6 5.52 6 6.68 6.08 7.52 8.16 7.72 8.52 8.56 9.2 9.16 8.92 7.44 6 5 3.48 2.92 2.16 2 2 1.2 1 1 1 1.24 1.64 1 1 1.96 2 2 2 1.76 1 1 1 0.52 1.76 3.64 5.12 6 6 6 6 5.52 4.24 2.36 0.88 0 0 0.68 1 1 1 1 1 1 1 0.32 0 0 1 1 1.44 2.44 3.68 5.4 6.88 7 6 6.52 6.76 6.56 5.32 3.6 2.92 3 3.72 3.96 3.8 3 3 3 2.2 2.4 2.28 1.52 1 1 1 1.72 2 1.6 1 1 1 1 1 0.28 0.92 2 2 2.72 3.64 4 4.84 5 4.08 3 3 2.68 2.36 2 1.16 1 1 2 4.92 4.6 4 4 4 4 4.32 4 1.08 1 1.52 2 2 2 1.68 1 1 1.32 1.48 1 1 1.52 2 2 2 1.68 1 1 1.88 1.48 1 1 1 1 1 1 0.12 0.4 1 1 1.2 3.88 4 5 5 4.6 4 4 3.8 2.08 2 1 1 1.44 2.4 3 
NR_047520 LOC643837 , 3 2.2 0.2 0 0 0.28 1 1 1 1 2.2 4.8 5 5.32 5 5 5 5 3.8 1.2 1 0.4 0 0 0 0 0 1 1 1 1 1 1 1 1.56 1 1 1 1 1 1 1 0.44 0.68 1 1.52 3 3.6 4.96 6.8 9 8.32 8.72 8.48 7 7.4 8.8 7.92 7.12 8.84 8.56 9.4 10.2 10 7.24 6.44 6.76 6.16 5.72 4.96 4.8 5.16 6 5.84 4.12 3 3 2.64 2.56 3.08 3 4.16 5 6.72 7 7.16 7.44 5.76 5 4.56 4 3.68 5 5.4 5.52 6 6 5.28 5 3.6 2 2.08 1.48 1 2 2 2 2 2 1.36 1 1 0 0 0.68 1 1 1 1 1 1 1 0.32 0 0 0 1.16 2 2 2 2 2.88 3 3 1.84 1 2 2 2.04 2.12 2 2 2 2 1 1.28 1.96 1.36 2.76 3 3 3 3 2.72 2 1.64 0.76 1 1.36 2 2 2 2 2 1.48 1 0.64 0 0.08 1 1 1.08 2 2 2 2 2.68 2 2 2.16 3.4 4 4 4.2 4.24 4 5.68 6.52 4.6 4 4 3.8 3.8 4 3.12 2.24 2.6 3 4 4 3.2 3 2.2 2 1.4 1.84 1.24 2 2 2 2 2 2 1.16 0.76 0 0 0 0 0 0 0 0.36 1 1.68 2 2 2.92 5.4 6.76 7.64 7 6.88 7 7.36 7.92 6.24 5.92 7.04 9.52 11.52 12.88 14.8 16.36 19.88 22.24 20 19.36 16.92 15.24 13.84 10.88 8.24 5.08 4.96 3.12 3 2.88 2 2.8 2.96 4 4.44 5 6 6 6 5.12 3.28 2 1.56 1 0.08 1.68 2 2 2.84 3 3 3.8 3.92 2.32 2 2.2 2.16 2 2 1.2 1 1 1 0.8 0 0 0 0.72 2.88 3 3 3 3 3 3 2.28 0.12 0 0.52 1 1 1 1 1.44 2 2 1.48 1 1 1 1.56 1.56 1 1 1 1 1 1 0.44 0.8 1.48 3 3 3 3 3 3.56 3.2 2.76 2 2 2 2 2.68 2.44 2 1.76 1 1.4 2 2 1.56 2 2 2 2 2.04 2 2 1.76 1 1 1 1 0.56 0 0 0 0 0 0 0 0 0.72 1.52 2 2 2 2 2 2 1.28 0.48                

Uwaga: składnia map jest ładny, ale jeśli plik jest duży należy używać pętli while za wydajność. Pętla natomiast unika czytania całego pliku do pamięci:

while (<DATA>) 
{ 
    if (/^([\w\s]*?)\s*,\s*(.*)/) 
    { 
     $line_max{$1} = max split ' ', $2; 
    } 
    else 
    { 
     print "Line $. is bad.\n"; 
    } 
} 
+0

Dziękuję za odpowiedź! Jest to kolejny sposób podejścia do problemu. Szczególnie podoba mi się ten wiersz '$ 1 => max split '', 2 $". Czy mógłbyś trochę o tym powiedzieć? Jest to nowatorska metoda dla mnie i chciałbym ją zrozumieć nieco więcej. – Neal

+1

@Neal, '$ 1',' $ 2', itp. Są specjalnymi zmiennymi, które posiadają podteksty pasujące do wyrażenia regularnego. Więc '$ 1' zawiera część linii, której używasz dla klawisza mieszającego. '$ 2' zawiera listę liczb. Następnie dzielę listę numerów na białe znaki, wybieram maksymalną wartość z tej listy i używam jej jako wartości skrótu. '=>' Jest po prostu fantazyjną wersją przecinka, często używanego do zapełniania skrótów: 'mój% hash = (klucz1 => 1, klucz2 => 123, klucz3 => 'foo')' – dan1111

+0

Ah! Wspaniałe podejście, panie! Sądzę, że nadszedł czas, aby uaktualnić czytanie czegoś poza książkę, o której mówiłem: "Początek Perla dla bioinformatyki" – Neal

Powiązane problemy