
Tengo varios archivos fastq delimitados por tabulaciones. Quiero hacer coincidir la segunda línea de cada lectura y sumar los valores junto a ella si coinciden. Por ejemplo:
file1.fq
>1
ATGCCGTT file1:1
+
HHHHKKKK
file2.fq
>2
ATGCCGTT file2:3
+
JJKHHTTT
>3
ATTCCAAC file2:1
+
=#GJLMNB
El resultado que quiero es como:
output.txt
ATGCCGTT file1:1 file2:3 count:4
ATTCCAAC file2:1 count:1
El código que he escrito es:
#!/usr/bin/env perl
use strict;
use warnings;
no warnings qw( numeric );
my %seen;
$/ = "";
while () {
chomp;
my ($key, $value) = split ('\t', $_);
my @lines = split /\n/, $key;
my $key1 = $lines[1];
$seen{$key1} //= [ $key ];
push (@{$seen{$key1}}, $value);
}
foreach my $key1 ( sort keys %seen ) {
my $tot = 0;
my $file_count = @ARGV;
for my $val ( @{$seen{$key1}} ) {
$tot += ( split /:/, $val )[0];
}
if ( @{ $seen{$key1} } >= $file_count) {
print join( "\t", @{$seen{$key1}});
print "\tcount:". $tot."\n\n";
}
}
Este código funciona bien para archivos pequeños, pero cuando quiero comparar archivos grandes, ocupa toda la memoria, lo que hace que el script se ejecute sin resultados. Quiero modificar el script para que no ocupe memoria. No quiero utilizar ningún módulo. Creo que si cargo solo un archivo en la memoria a la vez, ahorraré memoria pero no podré hacerlo. Por favor ayuda a modificar mi script.
Respuesta1
Has probado awk
? No estoy seguro de que maneje mejor archivos grandes, perl
pero podría valer la pena intentarlo:
Dentro de tu script awk:
BEGIN {
RS=">[0-9]+"
}
FNR==1{next}
NR==FNR {
a[$1]++
next
}
$1 in a {
b[$1]++
next
}
{
c[$1]++
}
END {
for (key in a) {
if (b[key] == "") {
printf key"\tfile1:"a[key]"\t\tcount:"a[key]"\n"
} else {
printf key"\tfile1:"a[key]"\tfile2:"b[key]"\tcount:"a[key]+b[key]"\n"
}
}
for (key in c) {
printf key"\t\tfile2:"c[key]"\tcount:"c[key]"\n"
}
}
Para ejecutarlo:
$ awk -f myscript.awk file1 file2 > output.txt
Lo probé con:
archivo1
>1
ATGCCGTT file1:1
+
HHHHKKKK
>2
ATTCCAACg file2:1
+
=#GJLMNB
archivo2
>2
ATGCCGTT file2:3
+
JJKHHTTT
>3
ATTCCAAC file2:1
+
=#GJLMNB
Salida en terminal:
ATTCCAACg file1:1 count:1
ATGCCGTT file1:1 file2:1 count:2
ATTCCAAC file2:1 count:1
Respuesta2
Añade estos encantamientos místicos a tu programa
use DB_File;
my %seen;
unlink '/tmp/translation.db';
sleep 2;
tie ( %seen, 'DB_File', '/tmp/translation.db' )
or die "Can't open /tmp/translation.db\n";
y su hash ya no residirá en la memoria sino en una base de datos en el disco. Puedes dejar el resto de tu código exactamente como está. Es cierto que utilicé el módulo DB_File pero realmente no hay razón para no hacerlo. Viene con cadaperlaInstalación lista para usar para que no tenga que instalarla ni nada.
Utilizo este enfoque todo el tiempo si mis hashes se vuelven realmente enormes y encuentro que, después de pasar un punto de amplitud vagamente definido, las cosas se aceleran bastante.