• Publicidad

Mi script que suma variables me tarda mucho

Perl aplicado a la bioinformática

Mi script que suma variables me tarda mucho

Notapor dzavallo » 2014-06-16 18:13 @801

Hola de nuevo, sigo aprendiendo a hacer scripts en Perl.

Hasta ahora tenía uno que me servía muy bien, pero ahora que tengo archivos más grandes me tarda muchísimo en correr (pronóstico: semanas), y querría saber si me pueden ayudar a optimizarlo.

Lo que tengo que hacer es lo siguiente: Tengo dos archivos con columnas. Los dos archivos son replicas de un experimento, y lo que necesito es sumar los datos que son iguales y grabarlos en otro archivo. Para reconocer que son iguales lo que hago es dividir las columnas de los archivos, y poner un condicional en donde si determinados ID cumplen las características, que me lo sumen.

Mi programa es el siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my $input1 = "/home/dzavallo/Downloads/sRNAs/M82_MZA/A/join/AA_join_repeats20";
  6. my $input2 = "/home/dzavallo/Downloads/sRNAs/M82_MZA/B/join/AB_join_repeats20";
  7. my $output = "/home/dzavallo/Downloads/sRNAs/M82_MZA/sumados/AB_repeats20_sumados";
  8. open( FILE1,      "<$input1.txt" )  or die "could not open $input1 file";
  9. open( OUTPUTFILE, ">>$output.txt" ) or die "could not $output.txt output file";
  10. while (<FILE1>) {                      ## 16    LTR     LTR:PGSC0003DMS000000392:567:723:1905:+ 13116   2947    26      SL2.50ch11      18600276        18600301
  11.     my @split1     = split( /\s/, $_ );
  12.     my $id1        = $split1[0];
  13.     my $id2        = $split1[1];
  14.     my $id3        = $split1[2];
  15.     my $countsRPM1 = $split1[4];
  16.     my $length1    = $split1[5];
  17.     my $chr1       = $split1[6];
  18.     my $coord1     = $split1[7];
  19.     my $coord2     = $split1[8];
  20.     open( FILE2, "<$input2.txt" ) or die "could not open $input2 file";
  21.  
  22.     while (<FILE2>) {                  ## 16    LTR     LTR:scaffold06318:1532:6859:6930:+      14108   2940    26      SL2.50ch06      42984094        42984119
  23.         my @split2     = split( /\s/, $_ );
  24.         my $id4        = $split2[0];
  25.         my $id5        = $split2[1];
  26.         my $id6        = $split2[2];
  27.         my $countsRPM2 = $split2[4];
  28.         my $length2    = $split2[5];
  29.         my $chr2       = $split2[6];
  30.         my $coord3     = $split2[7];
  31.         my $coord4     = $split2[8];
  32.         my $result     = $countsRPM1 + $countsRPM2;
  33.         if (    ( $id3 eq $id6 )
  34.             and ( $coord1 == $coord3 and $coord2 == $coord4 )
  35.             and ( $chr1 eq $chr2 )
  36.             and ( $length1 == $length2 ) ) {
  37.             print OUTPUTFILE "$id1\t$id2\t$id3\t$result\t$length1\t$chr1\t$coord1\t$coord2\n";
  38.             print "$countsRPM1\t$countsRPM2\t$result\n";
  39.             print
  40.                 "$id1\t$id4\t$id2\t$id5\t$id3\t$id6\t$result\t$length1\t$length2\t$chr1\t$chr2\t$coord1\t$coord3\t$coord2\t$coord4\n";
  41.         }
  42.     }
  43. }
  44.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Como ven, el condicional tiene que cumplir que los ID y los cromosomas sean los mismos, y además que las coordenadas sean las mismas, entre otras cosas.

Si es así, que imprima la suma y otras variables en un archivo de salida.

El tema es que los archivos tienen como 1 millón de líneas y al correrlo veo que cada suma tarda entre dos o tres segundos.

Entiendo que es un programa muy rudimentario y poco eficiente, ya que tiene que abrir y leer los archivos cada vez. ¿Tal vez un hash me ayude a optimizarlo?

¿Alguna ayuda de cómo podría hacerlo?

Me han dicho que con comandos de bash seguro que me anda más rápido (estilo awk y grep), pero quería probar y de paso aprender a tratar de hacerlo en Perl.

Gracias de antemano por cualquier ayuda que puedan darme.

Saludos.
dzavallo
Perlero nuevo
Perlero nuevo
 
Mensajes: 12
Registrado: 2013-01-08 11:39 @527

Publicidad

Re: Mi script que suma variables me tarda mucho

Notapor explorer » 2014-06-16 20:51 @910

Con comandos bash no conseguirás la velocidad que te puede dar Perl ;)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/local/bin/perl
  2. # JF 20140617
  3. use v5.14;
  4. use autodie;
  5.  
  6. ## Índices a las columnas
  7. use constant {
  8.         ID1             => 0,
  9.         ID2             => 1,
  10.         ID3             => 2,
  11.         CUENTARPM       => 4,
  12.         LARGO           => 5,
  13.         CHR             => 6,
  14.         COORD1          => 7,
  15.         COORD2          => 8,
  16. };
  17.  
  18. ## Leer archivo 2 y guardarlo en hash
  19. my %input2;
  20.  
  21. open my $FILE2, '<', 'AB_join_repeats20';
  22. while (<$FILE2>) {
  23.         chomp;                                                                                  # quitar finales de línea
  24.         my @campos = split;                                                                     # dividir
  25.         next if @campos != 9;                                                                   # si no hay 9 campos, saltar a la siguiente línea
  26.  
  27.         $input2{ join '|', @campos[ID3,COORD1,COORD2,CHR,LARGO] } = $campos[CUENTARPM];         # guardamos la cuenta RPM, pero indexada en el hash
  28. }
  29. close $FILE2;
  30.  
  31. #use Data::Dumper;
  32. #say Dumper \%input2;
  33.  
  34. ## Archivo de salida
  35. open my $OUTPUTFILE, '>', 'AB_repeats20_sumados';
  36.  
  37. ## Abrir y procesar el primer archivo
  38. open my $FILE1, '<', 'AA_join_repeats20';
  39. while (<$FILE1>) {
  40.         chomp;                                                          # quitar finales de línea
  41.         my @campos = split;                                             # dividir
  42.         next if @campos != 9;                                           # si no hay 9 campos, saltar a la siguiente línea
  43.  
  44.         my $indice = join '|', @campos[ID3,COORD1,COORD2,CHR,LARGO];    # componemos el índice
  45.  
  46.         if (exists $input2{ $indice }) {                                # si existe esa entrada en el archivo 2...
  47.  
  48.                 my $resultado = $campos[CUENTARPM] + $input2{$indice};  # hemos encontrado una coincidencia, hacemos la suma
  49.  
  50.                 say $OUTPUTFILE join "\t", @campos[ID1,ID2,ID3], $resultado, @campos[LARGO,CHR,COORD1,COORD2];
  51.         }
  52. }
  53. close $OUTPUTFILE;
  54. close $FILE1;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

P.D.: Estamos suponiendo que todos los registros del archivo dos son distintos. Si no es así, entonces, si los que son distintos son los del registro uno, pues cambiamos el orden de lectura y procesado de los archivos. Si se da el caso de que en los dos archivos hay registros repetidos... pues estamos hablando de otro problema distinto.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Mi script que suma variables me tarda mucho

Notapor dzavallo » 2014-06-17 08:50 @409

¡¡Muchas gracias!! ¡Funcionó a la perfección! ¡y rapidísimo!

Si los id1 son distintos para cada archivo, ¿hay forma de que aparezcan en el archivo de salida?

say $OUTPUTFILE join "\t", @campos[ID1,ID2,ID3], $resultado, @campos[LARGO,CHR,COORD1,COORD2];

Digamos que aparezcan el ID1 del archivo 1 y el ID1 del archivo2.

Muchas gracias de nuevo.
dzavallo
Perlero nuevo
Perlero nuevo
 
Mensajes: 12
Registrado: 2013-01-08 11:39 @527

Re: Mi script que suma variables me tarda mucho

Notapor explorer » 2014-06-17 09:42 @445

Sería algo así (no probado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/local/bin/perl
  2. # JF 20140617
  3. use v5.14;
  4. use autodie;
  5.  
  6. ## Índices a las columnas
  7. use constant {
  8.         ID1             => 0,
  9.         ID2             => 1,
  10.         ID3             => 2,
  11.         CUENTARPM       => 4,
  12.         LARGO           => 5,
  13.         CHR             => 6,
  14.         COORD1          => 7,
  15.         COORD2          => 8,
  16. };
  17.  
  18. ## Leer archivo 2 y guardarlo en hash
  19. my %input2;
  20.  
  21. open my $FILE2, '<', 'AB_join_repeats20';
  22. while (<$FILE2>) {
  23.         chomp;                                                                                  # quitar finales de línea
  24.         my @campos = split;                                                                     # dividir
  25.         next if @campos != 9;                                                                   # si no hay 9 campos, saltar a la siguiente línea
  26.  
  27.         my $indice = join '|', @campos[ID3,COORD1,COORD2,CHR,LARGO];                            # componemos el índice
  28.         $input2{ $indice } = [ @campos[ID1,CUENTARPM] ];                                        # guardamos la información, indexada, en el hash
  29. }
  30. close $FILE2;
  31.  
  32. #use Data::Dumper;
  33. #say Dumper \%input2;
  34.  
  35. ## Archivo de salida
  36. open my $OUTPUTFILE, '>', 'AB_repeats20_sumados';
  37.  
  38. ## Abrir y procesar el primer archivo
  39. open my $FILE1, '<', 'AA_join_repeats20';
  40. while (<$FILE1>) {
  41.         chomp;                                                          # quitar finales de línea
  42.         my @campos = split;                                             # dividir
  43.         next if @campos != 9;                                           # si no hay 9 campos, saltar a la siguiente línea
  44.  
  45.         my $indice = join '|', @campos[ID3,COORD1,COORD2,CHR,LARGO];    # componemos el índice
  46.  
  47.         if (exists $input2{ $indice }) {                                # si existe esa entrada en el archivo 2 (hay coincidencia)...
  48.                 my($id1,$cuentaRPM) = @{ $input2{$indice} };            # extraemos los valores guardados
  49.  
  50.                 my $resultado = $campos[CUENTARPM] + $cuentaRPM;        # hacemos la suma
  51.  
  52.                 say $OUTPUTFILE join "\t", $id1, @campos[ID1,ID2,ID3], $resultado, @campos[LARGO,CHR,COORD1,COORD2];
  53.         }
  54. }
  55. close $OUTPUTFILE;
  56. close $FILE1;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Bioinformática

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados

cron