Mesclar alguns arquivos delimitados por tabulação

3

Eu tenho 100 arquivos com 57.816 linhas cada. Eu quero fazer uma junção externa desses arquivos mesclando com base na coluna comum.

Estou usando a programação R para isso, mas isso é muito lento.

fileList <- list.files(, pattern=".txt")
pm_list=lapply(fileList, read.table)
merged_pm=merge_all(pm_list, by = "gene_short_name")

Existe alguma maneira rápida de fazer isso em bash? O outro método que eu posso usar é o SQL, mas eu tenho que criar 100 tabelas primeiro e depois carregá-las antes da junção, o que não é uma maneira muito eficiente de fazer.

O número de linhas é igual em cada arquivo, é por isso que eu quero mesclar com base na coluna comum e não posso usar o cbind de R como as constantes na coluna comum são um pouco para cima e para baixo em arquivos diferentes e não presentes no mesmo local em cada arquivo.Below são dois arquivos de exemplo.Eu quero juntar com base em 'gene_short_name'

gene_short_name FPKM56

MT-TF   0.90
MT-TV   0
MT-RNR1 310.015
MT-TL1  0
MT-TM   0

O arquivo 2 está abaixo:

gene_short_name FPKM53

MT-TF   0
MT-TV   0.344
MT-TM   0.10
MT-TL1  0
MT-RNR1 0
MT-ND2  158.332
    
por Ron 02.01.2015 / 20:36

2 respostas

3

O script a seguir deve fazer uma junção externa na coluna (campo) 1 de todos os arquivos delimitados por tabulação passados como argumentos. Ele usa o comando join , que faz uma junção externa em arquivos classificados, 2 arquivos de cada vez .

Ele se juntará a todas as linhas dos arquivos, incluindo as linhas de cabeçalho. Se você quiser que os cabeçalhos sejam excluídos, altere os dois comandos sort para algo que produza um arquivo classificado que os omita.

#!/bin/sh
if test $# -lt 2
then
    echo usage: gjoin file1 file2 ...
    exit 1
fi
sort -t $'\t' -k 1 "$1" > result
shift
for f in "$@"
do
    sort -t $'\t' -k 1 "$f" > temp
    join -1 1 -2 1 -t $'\t' result temp > newresult
    mv newresult result
done
cat result
rm result temp

Se você tem um shell mais antigo, $'\t' não será substituído por um tab, então você precisará usar ' TAB ' , onde você coloca uma tabulação literal entre as aspas.

Otimizações são possíveis se, em vez de /bin/sh , você puder usar um shell moderno como bash ou ksh; por exemplo, as linhas

sort -t $'\t' -k 1 "$f" > temp
join -1 1 -2 1 -t $'\t' result temp > newresult

pode ser substituído por

join -1 1 -2 1 -t $'\t' result <(sort -t $'\t' -k 1 "$f") > newresult
    
por 03.01.2015 / 02:36
2

Como, de acordo com sua postagem, as chaves na primeira coluna são sempre as mesmas (somente o pedido é diferente) Acho que você poderia fazer isso mais rapidamente com sort , cut e paste . Você poderia classificar um dos arquivos (excluindo as duas primeiras linhas) e, em seguida, classificar o restante dos arquivos (novamente, excluindo as duas primeiras linhas) e extrair apenas a segunda coluna de cada um deles e colar os resultados. Exemplo: 1.txt :

g_s_n   FPKM56

MT-ND2  21.06
MT-TF   0.90
MT-TV   1
MT-RNR1 310.015
MT-TL1  1
MT-TM   1

2.txt :

g_s_n   FPKM53

MT-TF   0
MT-TV   0.344
MT-TM   0.10
MT-TL1  0
MT-RNR1 0
MT-ND2  158.332

3.txt :

g_s_n   FPKM58

MT-RNR1 0.82
MT-TM   7
MT-TF   1.20
MT-TV   4
MT-ND2  4.05
MT-TL1  2

em execução:

paste <({ head -n 2; sort; } <1.txt) <({ head -n 2; sort; } <2.txt | cut -f2) \
<({ head -n 2; sort; } <3.txt | cut -f2)

produz:

g_s_n   FPKM56  FPKM53  FPKM58

MT-ND2  21.06   158.332 4.05
MT-RNR1 310.015 0   0.82
MT-TF   0.90    0   1.20
MT-TL1  1   0   2
MT-TM   1   0.10    7
MT-TV   1   0.344   4

Como funciona: { head -n 2; sort; } <1.txt classifica o primeiro arquivo (exceto as duas primeiras linhas), então a primeira coluna (comum) agora está classificada:

g_s_n   FPKM56

MT-ND2  21.06
MT-RNR1 310.015
MT-TF   0.90
MT-TL1  1
MT-TM   1
MT-TV   1

O mesmo vale para os outros arquivos: { head -n 2; sort; } <other_files.txt | cut -f2 , só que desta vez extraímos a segunda coluna (depois de sort , a primeira coluna é idêntica para todos os arquivos):

FPKM53

158.332
0
0
0
0.10
0.344

e:

FPKM58

4.05
0.82
1.20
2
7
4

estes são todos mesclados por paste .

Claro, o acima funciona bem para um número limitado de arquivos e se o seu shell suportar a substituição de processos. Caso contrário, você terá que escrever um script e usar arquivos temporários (como Mark faz em sua resposta), cole arquivos em lotes de 10, 20, etc, dependendo das limitações do seu sistema.

    
por 23.07.2015 / 00:07