Tengo un archivo de texto largo con las siguientes columnas, delimitadas por espacios:
Id Pos Ref Var Cn SF:R1 SR He Ho NC
cm|371443199 22 G A R Pass:8 0 1 0 0
cm|371443199 25 C A M Pass:13 0 0 1 0
cm|371443199 22 G A R Pass:8 0 1 0 0
cm|367079424 17 C G S Pass:19 0 0 1 0
cm|371443198 17 G A R Pass:18 0 1 0 0
cm|367079424 17 G A R Pass:18 0 0 1 0
Quiero generar una tabla que enumere cada ID única junto con los recuentos de:
- ¿Cuántas veces ocurrió esa identificación?
- ¿Cuántas de esas filas pasaban (columna 6)?
- ¿Cuántos tenían un
He
valor (columna 8)? - ¿Cuántos tenían un
Ho
valor (columna 9)
En este caso:
Id CountId Countpass CountHe CountHO
cm|371443199 3 3 2 1
cm|367079424 2 2 0 2
¿Cómo puedo generar esa tabla?
Respuesta1
Una forma de usar perl
asumir infile
tiene el contenido de su pregunta (las ID no estarán necesariamente en el mismo orden en la salida porque uso un hash para guardarlas):
Contenido de script.pl
:
use strict;
use warnings;
my (%data);
while ( <> ) {
## Omit header.
next if $. == 1;
## Remove last '\n'.
chomp;
## Split line in spaces.
my @f = split;
## If this ID exists, get previously values and add values of this
## line to them. Otherwise, begin to count now.
my @counts = exists $data{ $f[0] } ? @{ $data{ $f[0] } } : ();
$counts[0]++;
$counts[1]++ if substr( $f[5], 0, 4 ) eq q|Pass|;
$counts[2] += $f[7];
$counts[3] += $f[8];
splice @{ $data{ $f[0] } }, 0, @{ $data{ $f[0] } }, @counts;
}
## Format output.
my $print_format = qq|%-15s %-10s %-12s %-10s %-10s\n|;
## Print header.
printf $print_format, qw|Id CountId CountPass CountHe CountHo|;
## For every ID saved in the hash print acumulated values.
for my $id ( keys %data ) {
printf $print_format, $id, @{ $data{ $id } };
}
Ejecútelo como:
perl script.pl infile
Con la siguiente salida:
Id CountId CountPass CountHe CountHo
cm|371443198 1 1 1 0
cm|371443199 3 3 2 1
cm|367079424 2 2 0 2
Respuesta2
Aquí hay una solución awk
que utiliza 4 matrices para contar las 4 piezas de información que necesita. Luego, la salida awk
se alimenta, column
lo que alinea muy bien las columnas. (Tenga en cuenta que esto también se podría haber hecho awk
usando printf
.)
awk 'NR>1 {
id[$1]++
if($6 ~ /Pass/) pass[$1]++
if($8 ~ /1/) he[$1]++
if($9 ~ /1/) ho[$1]++
}
END {
print "Id CountId Countpass CountHe CountHO"
for(i in id)
print i" "id[i]" "(pass[i]?pass[i]:0)" "(he[i]?he[i]:0)" "(ho[i]?ho[i]:0)
}' input.txt | column -t
Producción:
Id CountId Countpass CountHe CountHO
cm|371443198 1 1 1 0
cm|371443199 3 3 2 1
cm|367079424 2 2 0 2