web-dev-qa-db-ja.com

タブ区切りのファイルをいくつかマージする

それぞれ57,816行の100個のファイルがあります。共通の列に基づいてマージすることにより、これらのファイルの外部結合を実行したいと思います。

私はこれにRプログラミングを使用していますが、これは非常に遅いです。

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

これをbashで行う簡単な方法はありますか?私が使用できるもう1つの方法はSQLですが、最初に100個のテーブルを作成してから、結合する前にそれらをロードする必要があります。これは、あまり効率的な方法ではありません。

各ファイルの行数は同じです。そのため、共通の列に基づいてマージしたいのですが、共通の列の定数は異なるファイルで少し上下し、同じ場所に存在しないため、Rのcbindを使用できません。以下は2つのサンプルファイルです。「gene_short_name」に基づいて結合したい

gene_short_name FPKM56

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

ファイル2は以下のとおりです。

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
3
Ron

次のスクリプトは、引数として渡されたすべてのタブ区切りファイルの列(フィールド)1で外部結合を実行する必要があります。 join コマンドを使用します。このコマンドは、ソートされたファイルに対して、一度に2つのファイルで外部結合を実行します。

ヘッダー行を含む、ファイル内のすべての行を結合します。ヘッダーを除外する場合は、2つのsortコマンドを、それらを省略したソート済みファイルを生成するものに変更します。

#!/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

古いシェルを使用している場合、$'\t'はタブに置き換えられないため、使用する必要があります 'TAB'、引用符の間にリテラルタブを配置します。

/bin/shの代わりに、bashやkshなどの最新のシェルを使用できる場合は最適化が可能です。たとえば、行

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

に置き換えることができます

join -1 1 -2 1 -t $'\t' result <(sort -t $'\t' -k 1 "$f") > newresult
3
Mark Plotnick

投稿ごとに、最初の列のキーは常に同じであるため(順序のみが異なります)、sortcut、およびpasteを使用するとこれをより速く行うことができると思います。 。ファイルの1つ(最初の2行を除く)を並べ替えてから、残りのファイル(ここでも、最初の2行を除く)を並べ替え、各ファイルから2番目の列のみを抽出して、結果を貼り付けることができます。例:
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

ランニング:

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

生成:

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

使い方: { head -n 2; sort; } <1.txt最初のファイル(最初の2行を除く)を並べ替えるので、最初の列(共通)が並べ替えられます。

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

他のファイルについても同じです:{ head -n 2; sort; } <other_files.txt | cut -f2、今回のみ2番目の列を抽出します(sortの後、最初の列はすべてのファイルで同一です):

FPKM53

158.332
0
0
0
0.10
0.344

そして:

FPKM58

4.05
0.82
1.20
2
7
4

これらはすべてpasteによってマージされます。


確かに、上記は限られた数のファイルで、シェルがプロセス置換をサポートしている場合は問題なく機能します。それ以外の場合は、スクリプトを作成して一時ファイルを使用し(Markが回答で行っているように)、システムの制限に応じてファイルを10、20などのバッチで貼り付ける必要があります。

2
don_crissti