一部の共有列を使用してCSVに参加する

一部の共有列を使用してCSVに参加する

9GB程度の大容量ファイルが2つあります。 CSVファイル1には列があり、A, B, C, D, ECSVファイル2には列がありますB, C, F, G。希望の出力はですA, B, C, D, E, F, G。私が見つけることができるのは、同じ列を結合して同じ列に関連付けることです。ただし、ここでは一部が一致し、一部は一致しません。サンプル出力は次のとおりです。

A   B   C   D   E   F   G

1   2   3   4   5   6   7

NaN 1   2   NaN 1   2   1

したがって、列の値がない場合は存在しないものと同じで、値のみを持ちたいですNaN。問題を十分に説明したことを願っています。ありがとうございます!

編集:通常これを行いますが、Pythonこのような大きなファイルのためにチャンクを繰り返して最後にリンクする方が面倒です。bash私が知らないより直接的な使用方法があるようです。ありがとうございます!

答え1


(a) すべてのフィールドは厳密にタブで区切られます。 (
b)2つのファイル(BとC)の共通列は同じ値を持ちます。

$ join --nocheck-order -eNaN -13 -22 -t$'\t' -o 1.1 1.2 1.3 1.4 1.5 2.3 2.4 b.txt c.txt
A   B   C   D   E   F   G
1   2   3   4   5   6   7
NaN 1   2   NaN 1   2   1

ファイルサンプル:

$ cat b.txt
A   B   C   D   E
1   2   3   4   5
    1   2       1
$ cat c.txt
B   C   F   G
2   3   6   7
1   2   2   1

接続オプション:
-13 -22: ファイル 1 列 3(C) = ファイル 2 列 2(C) に基づいて結合
-t$'\t': 入力と出力のタブ区切り記号
-o: 出力形式。 1.1はファイル1、列1などを意味します。
-e: 空の値を NaN で埋めます。
詳しくはman joinEven Betterをご覧ください。info join

AWKを使用した代替ソリューション
PS:awkについて忍耐を持ってください。私はawkを初めて学ぶ人です。

$ awk -F"\t" '{a[1]="";{for (i=1;i<=NF;i++) if (i==6 ||i==7) continue;else \
if ($i!="") a[1]=a[1]FS$i;else a[1]=a[1]FS"NaN";print a[1]}}' <(paste b.txt c.txt)

カンマ区切り入力フィールドの更新
あなたのコメントが示唆したように、csvファイルはカンマで区切られているため、このソリューションは入力フィールドをカンマで区切ってタブを使用して結果を読みやすくします。

awk 'BEGIN {FS=",";OFS="\t"}{a[1]="";{for (i=1;i<=NF;i++) if (i==6 ||i==7) continue;else \
if ($i!="") a[1]=a[1]OFS$i;else a[1]=a[1]OFS"NaN";print a[1]}}' <(paste b.txt c.txt)

出力をコンマで印刷する必要がある場合は、先頭を次に置き換えます。{FS=OFS=","}

共通の列/他の値を処理する方法はまだ明確ではありません。

部品を取り外して、if (i==6 ||i==7) continue;else結果がニーズに合っているかどうかを確認できます。この条件付きチェックは、これまでファイル2の2つの列がファイル1の列と同じように処理されていたため、実際にはフィールド6(ファイル2の列B)とフィールド7(ファイル2の列C)をスキップします。

結合ソリューションの場合:カンマ区切りのフィールドを読むには、次のように
置き換えます。-t$'\t'-t','

共通列の場合は、次の出力形式を使用できます。

join --nocheck-order -eNaN -13 -22 -t',' -o 1.1 1.2 2.1 1.3 2.2 1.4 1.5 2.3 2.4 b.txt c.txt

関連情報