• Publicidad

Cómo sumar elementos escalares numéricos dentro de un array

Perl aplicado a la bioinformática

Cómo sumar elementos escalares numéricos dentro de un array

Notapor dzavallo » 2013-01-09 11:51 @535

Hola a todos, soy bastante nuevo en programación en Perl y quiero hacer un script que me haga lo siguiente:

Tengo una lista de genes con números:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
AT1G01073 18,5
AT1G02470 20
AT1G02590 5
AT1G02590 6,5
AT1G02740 5,5
AT1G03600 5,5
AT1G03600 9
AT1G03600 4,5
AT1G03600 8
AT1G03600 6
AT1G03600 11,5
AT1G03600 4
AT1G04410 4,5
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Lo que quiero hacer es sumar los números correspondientes a cada gen, pero como verán, algunas son únicas, y otros tienen más de una fila por gen.

Tengo que hacer un script para que me sume las que están repetidas y me deje una única, y obviamente las que están únicas las deje igual y que quede algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
AT1G01073 18,5
AT1G02470 20
AT1G02590 11,5
AT1G02740 5,5
AT1G03600 48,5
AT1G04410 15,5
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Empecé a escribir el script pero no puedo sumar los elementos (números) que puse dentro en un array, para luego exportarlos junto con su id.

¿Existe una función para sumar escalares numéricos?

Agradecería su ayuda
Muchas gracias

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my $input2
  6.     = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_genes_sin_sumar";
  7. my $input1 = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_ids";
  8. my $output
  9.     = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_genes_sumados";
  10. open( FILE1,      "<$input1.txt" )  or die "could not open $input1 file";
  11. open( OUTPUTFILE, ">>$output.txt" ) or die "could not open $output file";
  12. while (<FILE1>) {                      # AT1G01073
  13.     my @split1 = split( /\s+/, $_ );
  14.     chomp $_;                          # borra las lineas vacias
  15.     my $id1 = $_;
  16.     my @array;                         # defino el array que va a contener las cuentas de id repetidos
  17.     open( FILE2, "<$input2.txt" ) or die "could not open $input2 file";
  18.     while (<FILE2>) {                  # AT1G01073 6
  19.         my @split2 = split( /\s+/, $_ );
  20.         my $id2    = $split2[0];
  21.         my $counts = $split2[1];
  22.         chomp $_;
  23.         if ( $id1 eq $id2 ) {
  24.             push( @array, $counts );   #como sumo $counts para luego imprimirlos?
  25.  
  26.             print OUTPUTFILE "$id1\t$counts\n"
  27.  
  28.         }
  29.     }
  30. }
  31.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2013-01-09 12:12 @550, editado 1 vez en total
Razón: Formateado de código con Perltidy y poner marcas Perl
dzavallo
Perlero nuevo
Perlero nuevo
 
Mensajes: 12
Registrado: 2013-01-08 11:39 @527

Publicidad

Re: Cómo sumar elementos escalares numéricos dentro de un ar

Notapor dzavallo » 2013-01-09 12:53 @578

Soy yo de nuevo, una cosa que se me ocurrió pero que no funciona, es crear una nueva variable $total, y que esa sume los elementos dentro del @array

Puede ser así:

push (@array, $counts);
my $total +=$counts ;
print OUTPUTFILE "$id1\t$total\n"

De todos modos no me funciona y sigue exportándome el mismo archivo inicial.

¿alguna sugerencia?

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

Re: Cómo sumar elementos escalares numéricos dentro de un ar

Notapor explorer » 2013-01-09 12:59 @582

Bienvenido a los foros de Perl en Español, dzavallo.

Este es un problema típico que se puede resolver muy fácilmente con un hash.

Solo tienes que guardar como claves del hash el nombre de los genes, y como valores, vas acumulando los valores que vas leyendo.

Así, al final, tendrás la suma separada por cada gen, tanto si ha aparecido una sola vez, o cien.

Un detalle: para que Perl haga las sumas correctas, los números, deben tener notación anglosajona: debes cambiar las comas separadoras de la parte fraccionaria por puntos.
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: Cómo sumar elementos escalares numéricos dentro de un ar

Notapor dzavallo » 2013-01-09 13:42 @612

explorer, muchas gracias por tu respuesta.

Mientras esperaba se me ocurrió otra manera para solucionarlo y funcionó, pero seguramente con la que tu dices es mucho más rápida.

Entiendo que al asignar las keys al %hash ¿automáticamente me va a sumar las cuentas?
¿O tu respuesta era para resolver la última parte del script?

Te muestro el script con mi solución final, probablemente sea muy redundante y frente a archivos enormes tarde mucho, ¿no es así?

Muchas gracias nuevamente, muy bueno el foro.


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3.  
  4.  
  5. my $input2 = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_genes_sin_sumar";
  6. my $input1 = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_ids";
  7. my $output = "/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO/NI_4dpi_genes_sumados1";
  8. open(FILE1, "<$input1.txt") or die "could not open $input1 file";
  9. open(OUTPUTFILE, ">>$output.txt") or die "could not open $output file";
  10. while (<FILE1>) {       # AT1G01073 (lee de a una las lineas del file1)
  11.         my @split1 = split (/\s+/, $_); # spliteo por espacios las columnas
  12.         chomp $_; # borra las lineas vacías
  13.         my $id1 = $_; # defino la columna id1
  14.         my @array; # defino el array que va a contener las cuentas de id repetidos
  15.         open(FILE2, "<$input2.txt") or die "could not open $input2 file";
  16.         while (<FILE2>) { # AT1G01073 6 (este es otro loop dentro del primer loop y también lee de a una las lineas del file2
  17.                 my @split2= split (/\s+/, $_);
  18.                 my $id2 = $split2[0]; # defino el id2
  19.                 my $counts = $split2[1]; # defino las cuentas
  20.                 chomp $_;
  21.                 if ($id1 eq $id2) {
  22.                         push (@array, $counts); # si id1= id2 mete en un array las cuentas (esto puede ser uno solo o varios números)
  23.                 } #cierro el loop if
  24.         } #cierro el loop while del file2
  25.         my $total = 0; #defino la variable total con un 0 para que sepa que es numérica
  26.         foreach (@array) { # para cada elemento del array
  27.                 $total = $total + $_; # sumo la variable total=0 al primer elemento del array, y luego ese total lo suma al siguiente elemento y así hasta que se terminen los elementos del array
  28.         } #cierro el lop foreach
  29.         print OUTPUTFILE "$id1\t$total\n"
  30. }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
dzavallo
Perlero nuevo
Perlero nuevo
 
Mensajes: 12
Registrado: 2013-01-08 11:39 @527

Re: Cómo sumar elementos escalares numéricos dentro de un ar

Notapor explorer » 2013-01-09 18:28 @811

Pues sí, puede ser muy lento si los archivos son muy grandes.

No, los hash no suman de forma predeterminada. Solo guardan los valores que le indiquemos. Si es una suma, pues el resultado de la suma.

Esta es la versión más pequeña.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;                    # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  4.  
  5. my $ruta = '/home/diego-ubuntu/0-archivos_deep_seq/DEEP_SEQ1_4dpi/promedios/TAIR/RPM_mapeables/GO';
  6. my $archivo_a_procesar = "$ruta/NI_4dpi_genes_sin_sumar";
  7. my $archivo_resultado  = "$ruta/NI_4dpi_genes_sumados1";
  8.  
  9. my %genes;
  10.  
  11. open my $GENES, '<', $archivo_a_procesar;
  12. while (<$GENES>) {              # leemos una línea, mientras no lleguemos al final
  13.     chomp;                      # quitamos el carácter de nueva línea
  14.  
  15.     my($gen, $valor) = split;   # partimos
  16.  
  17.     $valor =~ s/[,]/./;         # pasamos a notación anglosajona
  18.  
  19.     $genes{$gen} += $valor;     # acumulamos
  20. }
  21. close $GENES;
  22.  
  23. open my $SALIDA, '>', $archivo_resultado;
  24. while (my($gen, $valor) = each %genes) {       # para cada par clave/valor
  25.     say $SALIDA "$gen $valor";                 # los mandamos a la $SALIDA
  26. }
  27. close $SALIDA;
  28.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Sale:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
AT1G04410 4.5
AT1G02470 20
AT1G01073 18.5
AT1G03600 48.5
AT1G02740 5.5
AT1G02590 11.5
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Como ves, toda la operación se reduce a la línea 19, donde vamos acumulando los valores según el $gen que hayamos leído.

Imagínate un archivador que tiene un cajón por cada gen. Por cada línea que leemos, buscamos el cajón del gen, lo abrimos, y acumulamos el valor que tenía con el nuevo valor leído.
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: Cómo sumar elementos escalares numéricos dentro de un ar

Notapor dzavallo » 2013-01-10 09:45 @448

explorer, ¡muchas gracias por tu ayuda!
Probé el script y efectivamente corre mucho más rápido.
Muy bueno el foro, lo seguiré consultando.
dzavallo
Perlero nuevo
Perlero nuevo
 
Mensajes: 12
Registrado: 2013-01-08 11:39 @527


Volver a Bioinformática

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron