如何交叉检查另一个文件中的一列并打印缺失值?

如何交叉检查另一个文件中的一列并打印缺失值?

我有一个看起来像这样的文件。它有 12 列和 3244343 行。我们将此文件命名为 1。

variant_id  gene_id tss_distance    ma_samples  ma_count    maf pval_nominal    slope   slope_se    pval_nominal_threshold  min_pval_nominal    pval_beta
chr10_100000235_C_T_b38 ENSG00000227232.5   35211   73  74  0.061157    1.69779e-08 0.510322    0.0890939   0.0006160191.01823e-08  1.17701e-05
chr10_100002628_A_C_b38 ENSG00000227232.5   635545  126 130 0.107438    1.01823e-08 0.405406    0.0696647   0.0006160191.01823e-08  1.17701e-05
chr1_666028_G_A_b38 ENSG00000227232.5   636475  111 115 0.0950413   2.78462e-08 0.411513    0.0729864   0.0006160191.01823e-08  1.17701e-0

我有另一个文件,如下所示,有 7 个标题和 1633293 行。这是文件2。

"variant_id" "hg38_chr" "hg38_pos" "ref_allele" "alt_allele" "hg19_chr" "hg19_pos"
"chr10_100000235_C_T_b38" "chr10" "100000235" "C" "T" "chr10" 101759992
"chr10_100002628_A_C_b38" "chr10" "100002628" "A" "C" "chr10" 101762385
"chr10_100004827_A_C_b38" "chr10" "100004827" "A" "C" "chr10" 101764584
"chr10_100005358_G_C_b38" "chr10" "100005358" "G" "C" "chr10" 101765115

我只对variant_id专栏感兴趣。这是两个文件中的第一列。

如何比较这两列并仅打印variant_id第一列中的那些值在第二个文件中找不到。对于上面的例子,输出应该是

chr1_666028_G_A_b38 

因为它在第一个文件中找到,但在第二个文件中找不到。

第二个文件中的所有值variant_id也都在第一个文件中。但第一个文件中有额外的 ID,第二个文件中不存在,我想识别这些 ID。

答案1

如果您使用的系统支持流程替代,您可以grep-v标志(显示不匹配的行)和-f标志(从文件中读取模式)一起使用,其中“文件”是一个仅打印文件第一个字段的命令。例如:

$ grep -vf <(awk '{print $1}' file2) file1
variant_id  gene_id tss_distance    ma_samples  ma_count    maf pval_nominal    slope   slope_se    pval_nominal_threshold  min_pval_nominal    pval_beta
"chr1_666028_G_A_b38"   ENSG00000227232.5   636475  111 115 0.0950413   2.78462e-08 0.411513    0.0729864   0.0006160191.01823e-08  1.17701e-0

如果这不是一个选项,您可以将第一个字段打印到文件中并使用它:

$ awk '{print $1}' file2 > file2.names
$ grep -vf file2.names file1
variant_id  gene_id tss_distance    ma_samples  ma_count    maf pval_nominal    slope   slope_se    pval_nominal_threshold  min_pval_nominal    pval_beta
"chr1_666028_G_A_b38"   ENSG00000227232.5   636475  111 115 0.0950413   2.78462e-08 0.411513    0.0729864   0.0006160191.01823e-08  1.17701e-0

或者,假设您有足够的 RAM 来保存 file2 中的所有变体 ID(除非您使用的是非常旧的硬件,否则您应该这样做),您可以使用awk存储一个文件的所有第一个字段,然后检查另一个文件中的它们:

$ awk 'NR == FNR{a[$1]++;next}; !($1 in a)' file2 file1
variant_id  gene_id tss_distance    ma_samples  ma_count    maf pval_nominal    slope   slope_se    pval_nominal_threshold  min_pval_nominal    pval_beta
"chr1_666028_G_A_b38"   ENSG00000227232.5   636475  111 115 0.0950413   2.78462e-08 0.411513    0.0729864   0.0006160191.01823e-08  1.17701e-0

答案2

我首先对这两个文件进行排序(当然不包括标题)。然后,我将使用awkcut选择第一列(减去标题)并使用过程替换来选择不在 中的comm列:file1file2

comm -23 <(awk 'NR>1 {print $1;}' file1) <(awk 'NR >1 {print $1;}' file2)

您可以通过将进程替换 [1] 中的命令重构为脚本来进行较小的简化,例如col1-nh(“第一列,无标题”):

#! /bin/bash

file=$1

awk 'NR>1 {print $1;}' $file

命令将是:

comm -23 <(col1-nh file1) <(col1-nh file2)

同样,这假设文件的主体是已排序。但这是O(N logN)并且两者都是col1-nhcomm其中O(N)N 是行数,因此它应该能够毫无问题地处理您提到的大小的文件。您当然应该测量每个建议的解决方案所花费的时间。


[1] 尽管@terdon 建议NR>1awk调用中使用,但sed不再需要,并且人们可能会认为该命令本身就足够简单了。

相关内容