Text-Processing

將 CSV 與一些共享列連接起來

  • February 15, 2017

我有兩個大文件~9GB。CSV 文件 1 有列A, B, C, D, E,CSV 文件 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我不知道的更直接的使用方式。謝謝!

這基於以下事實:

(a)所有欄位都嚴格用製表符分隔

(b)兩個文件(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:連接基於 file1 column3 (C) = file2 column2 (C)

-t$’\t’:輸入和輸出的製表符分隔符

-o:輸出格式。1.1 表示 file1、column1 等。

-e :用 NaN 填充空值

有關更多資訊,請參閱man join甚至更好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)

如果您還需要用逗號列印輸出,只需將 begine 部分替換為{FS=OFS=","}

儘管仍不清楚您打算如何處理公共列/不同的值。

您可以移除零件if (i==6 ||i==7) continue;else以查看結果是否符合您的需求。此條件檢查實際上跳過了欄位 6(文件 2 的 B 列)和欄位 7(文件 2 的 C 列),因為到目前為止,文件 2 的這兩列被認為與文件 1 的列相同。

對於連接解決方案:

替換-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

引用自:https://unix.stackexchange.com/questions/345051