部分的に一致するキー列を持つ複数のCSVファイルをマージする

部分的に一致するキー列を持つ複数のCSVファイルをマージする

100個のファイルがあり、csv各ファイルには2つの列が含まれています。最初のものはでtaxonomy、2番目はですcounts。各ファイルには約10,000行があります。各ファイルのデータはtaxonomy部分的にのみ共有され、合計約50,000の固有値があります。taxa1つのファイルから欠落している項目に値が割り当てられたテーブルにマージする必要があります0。結果は、50,000行と101列のテーブルでなければなりませんcsvtsv単純化された例は次のとおりです。ファイル 1( R1.csv):

A,1
B,20
C,30

ファイル 2( R2.csv):

C,1
D,13
E,15
F,19

ファイル3(R3.csv):

A,1
B,4
E,2
G,6
H,8

予想される結果:

Taxa,R1,R2,R3
A,1,0,1
B,20,0,4
C,30,1,0
D,0,13,0
E,0,15,2
F,0,19,0
G,0,0,6
H,0,0,8

bashスクリプトを使ってこれを行う方法を知っていますか?

ベストアンサー1

私はawkこれを使用して複数のファイルを一度に処理します。

sed 's/,R[1-9]\+\.csv:/,/g' <(awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" -F, '
    { seen[$1]=seen[$1]","FILENAME":"$2; }
    END { print HEADER; for (x in seen) print x seen[x]}' R{1..3}.csv \
|awk -F, 'NR==1{split($0,arr,/,/);next} {SEP=""; fld=1;
    for (x in arr){printf ($0 ~ arr[x])?SEP""$(fld++):",0";SEP=","};print ""}')

出力:

A,1,0,1
B,20,0,4
C,30,1,0
D,0,13,0
E,0,15,2
F,0,19,0
G,0,0,6
H,0,0,8

コード分​​析:

awk -F, '{ seen[$1]=seen[$1]","FILENAME":"$2; }
    END{ print HEADER; for (x in seen) print x seen[x] }' R{1..3}.csv

コードの主要部分は、すべてのファイルの2番目の列をすべて1つに連結し、同じ最初の列を持つファイルに属する値を印刷します。以下は、キーが最初の列で値が追加モードの配列seen名です。,FILENAME:$2

Inは、seen[$1]=seen[$1]","FILENAME":"$2;カンマを印刷し、,その後に現在処理されているFILENAMEファイルを印刷することを意味します。アッ、コロン:の後に2番目の列の値が続きます$2(最初の列が同じ場合)。seen[$1]=...同じキーインデックスに追加され、=seen[$1]...同じキー値に保存されます。

このEND声明は、アッこのブロックはすべてのレコード/行を読み取ると最終的に実行され、forループを使用して配列を繰り返します。ボン印刷して最初とコア値次から。

結果は次のとおりです。

A,R1.csv:1,R3.csv:1
B,R1.csv:20,R3.csv:4
C,R1.csv:30,R2.csv:1
D,R2.csv:13
E,R2.csv:15,R3.csv:2
F,R2.csv:19
G,R3.csv:6
H,R3.csv:8

さて、既存の値がどのファイルから来たのか、どのファイルにこのデータがないのかがわかります。存在しないファイルをデータで埋めるために0シェルコマンドを使用しました。すべてのファイル名を含むヘッダー行の生成そして配信アッ〜のようにHEADER -V可変的な:

awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" ...

HEADER後でこの行を使用します0。現在の入力形式は次のとおりです。

$ awk -v HEADER="$(printf ",%s:" R{1..3}.csv)" -F, '
    { seen[$1]=seen[$1]","FILENAME":"$2; }
    END { print HEADER; for (x in seen) print x seen[x]}' R{1..3}.csv 
,R1.csv:,R2.csv:,R3.csv:
A,R1.csv:1,R3.csv:1
B,R1.csv:20,R3.csv:4
C,R1.csv:30,R2.csv:1
D,R2.csv:13
E,R2.csv:15,R3.csv:2
F,R2.csv:19
G,R3.csv:6
H,R3.csv:8

次に、以下の他のものを使用しました。アッ終了しないファイルデータを埋めるスクリプト、0質問に対する他の回答からこのデータをコピーしました。「列に基づいて書式設定し、不足しているデータを埋める」

... |awk -F, 'NR==1{split($0,arr,/,/);next} {SEP=""; fld=1;
    for (x in arr){printf ($0 ~ arr[x])?SEP""$(fld++):",0";SEP=","};print ""}'

最後に、sed 's/,R[1-9]\+\.csv:/,/g'結果の既存のファイル名を単一のコンマに変更するために使用します,

おすすめ記事