将 CSV 与一些共享列连接起来

将 CSV 与一些共享列连接起来

我有两个大文件~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

相关内容