2011-08-04 16 views
9

que tengo un archivo de texto que se parece a esto:Perl (o R, o SQL): Contar con qué frecuencia aparece cadena través de las columnas

gene1 gene2 gene3 
a  d  c 
b  e  d 
c  f  g 
d  g  
     h 
     i 

(Cada columna es un gen humano, y cada una contiene un número variable de proteínas (cadenas, que se muestran como letras aquí) que pueden unirse a esos genes).

Lo que quiero hacer es contar el número de columnas cada cadena está representado en, salida de ese número y todos los encabezados de columna, como este:

a 1 gene1 
b 1 gene1 
c 2 gene1 gene3 
d 3 gene1 gene2 gene3 
e 1 gene2 
f 1 gene2 
g 2 gene2 gene3 
h 1 gene2 
i 1 gene2 

He estado tratando de encontrar la manera de hacer esto en Perl y R, pero sin éxito hasta el momento. Gracias por cualquier ayuda.

+0

¿Están las columnas delimitadas por tabuladores o tienen formato de espacio? Eso dictará cómo tratarlos. –

Respuesta

8

Esta solución parece un poco pirata, pero da la salida deseada. Se basa en el uso de los paquetes plyr y reshape, aunque estoy seguro de que podría encontrar alternativas de base R. El truco es que la función melt nos permite aplanar los datos en un formato largo, lo que permite una manipulación fácil (ish) desde ese punto en adelante.

library(reshape) 
library(plyr) 

#Recreate your data 
dat <- data.frame(gene1 = c(letters[1:4], NA, NA), 
        gene2 = letters[4:9], 
        gene3 = c("c", "d", "g", NA, NA, NA) 
       ) 

#Melt the data. You'll need to update this if you have more columns 
dat.m <- melt(dat, measure.vars = 1:3) 

#Tabulate counts 
counts <- as.data.frame(table(dat.m$value)) 

#I'm not sure what to call this column since it's a smooshing of column names 
otherColumn <- ddply(dat.m, "value", function(x) paste(x$variable, collapse = " ")) 

#Merge the two together. You could fix the column names above, or just deal with it here 
merge(counts, otherColumn, by.x = "Var1", by.y = "value") 

Da:

> merge(counts, otherColumn, by.x = "Var1", by.y = "value") 
    Var1 Freq    V1 
1 a 1    gene1 
2 b 1    gene1 
3 c 2  gene1 gene3 
4 d 3 gene1 gene2 gene3 
.... 
+0

Gracias, siempre me encanta una solución R, especialmente usando las funciones ** plie. –

+2

puede simplificar en una sola llamada 'ddply' usando' ddply (dat.m,. (value), summarize, Freq = length (variable), V1 = paste (variable, collapse = "")) ' – Ramnath

1

Si no hay muchas columnas, puede hacer algo como esto en sql. Básicamente, aplana los datos en una tabla derivada de proteína/gen de 2 columnas y luego resúmelos según sea necesario.

;with cte as (
    select gene1 as protein, 'gene1' as gene 
    union select gene2 as protein, 'gene2' as gene 
    union select gene3 as protein, 'gene3' as gene 
) 

select protein, count(*) as cnt, group_concat(gene) as gene 
from cte 
group by protein 
+1

err, pero la parte difícil es aplanamiento de los datos – ysth

+0

Gracias. He pensado hacerlo de esta manera en MySQL, pero tengo bastantes columnas. Voy a intentar esto si es necesario, tal vez escribir algún código perl para escribir mi consulta, ugh. –

6

En perl, suponiendo que las proteínas de cada columna no tienen duplicados que deban eliminarse. (Si lo hacen, un hash de hashes se debe utilizar en su lugar.)

use strict; 
use warnings; 

my $header = <>; 
my %column_genes; 
while ($header =~ /(\S+)/g) { 
    $column_genes{$-[1]} = "$1"; 
} 

my %proteins; 
while (my $line = <>) { 
    while ($line =~ /(\S+)/g) { 
     if (exists $column_genes{$-[1]}) { 
      push @{ $proteins{$1} }, $column_genes{$-[1]}; 
     } 
     else { 
      warn "line $. column $-[1] unexpected protein $1 ignored\n"; 
     } 
    } 
} 

for my $protein (sort keys %proteins) { 
    print join("\t", 
     $protein, 
     scalar @{ $proteins{$protein} }, 
     join(' ', sort @{ $proteins{$protein} }) 
    ), "\n"; 
} 

lee de la entrada estándar, escribe en la salida estándar.

+0

Perfecto. Gracias. –

+0

No estoy familiarizado con la sintaxis $ hash {$ - [1]}. ¿Qué está haciendo esto? –

+2

'@ -' es una matriz especial que informa la posición en la que se inició una captura de expresiones regulares (' $ - [1] 'donde' $ 1' comenzó, '$ _ [2]' para '$ 2', etc.) – ysth

5

A un trazador de líneas (o más bien 3 liner)

ddply(na.omit(melt(dat, m = 1:3)), .(value), summarize, 
    len = length(variable), 
    var = paste(variable, collapse = " ")) 
1

en MySQL, así:

select protein, count(*), group_concat(gene order by gene separator ' ') from gene_protein group by protein; 

datos asumir como:

create table gene_protein (gene varchar(255) not null, protein varchar(255) not null); 
insert into gene_protein values ('gene1','a'),('gene1','b'),('gene1','c'),('gene1','d'); 
insert into gene_protein values ('gene2','d'),('gene2','e'),('gene2','f'),('gene2','g'),('gene2','h'),('gene2','i'); 
insert into gene_protein values ('gene3','c'),('gene3','d'),('gene3','g'); 
Cuestiones relacionadas