我有两个大文件~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
我不知道的更直接的使用方法。谢谢!
答案1
这是基于以下事实:
(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 :基于文件 1 列 3 (C) = 文件 2 列 2 (C) 进行连接
-t$'\t' :输入和输出的制表符分隔符
-o :输出格式。 1.1 表示文件 1、列 1 等。
-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