如何过滤两个文件中特定列中的值具有相同符号(- 或 +)的行?

如何过滤两个文件中特定列中的值具有相同符号(- 或 +)的行?

我有两个文件,如下所示:

  • file1:
    6:66893424_T_C -0.5985 
    rs151222586 -0.0351 
    rs12364336 -0.0030 
    rs57502521 0.0099 
    
  • file2:
    6:66893424_T_C 0.5985
    rs151222586 -0.0351
    rs12364336 0.003
    rs57502521 -0.0099
    

我想:

  • 找到第 2 列具有相同符号(减号或加号)的行
  • 创建符号匹配的 column1 条目列表
  • 创建一个列 1 条目的列表,其中 不匹配

我想:

  • 匹配的输出为
    rs151222586
    
  • 和一个无与伦比的输出
    6:66893424_T_C
    rs12364336
    rs57502521
    

答案1

并排粘贴+awk 文件,以便我们可以将第二个字段与第四个字段进行比较:

paste file1 file2 |
awk '
  $2&&$4 {
    print $1 > ($2*$4>0?"match":"unmatch")
  }
'

结果在文件中匹配和不匹配。

答案2

处理多个输入文件是一件苦差事,如果将数据折叠到单个文件中会更容易。例如pastejoin可以这样做:

$ paste file1 file2
6:66893424_T_C -0.5985  6:66893424_T_C 0.5985
rs151222586 -0.0351     rs151222586 -0.0351
rs12364336 -0.0030      rs12364336 0.003
rs57502521 0.0099       rs57502521 -0.0099

$ join -j1 file1 file2
6:66893424_T_C -0.5985  0.5985
rs151222586 -0.0351  -0.0351
rs12364336 -0.0030  0.003
rs57502521 0.0099  -0.0099

前者依赖于顺序正确。在这两种情况下,您可能应该检查文件是否彼此不一致。

使用 的输出paste,符号不同的条目:

$ paste file1 file2 | awk '($2 >= 0) != ($4 >= 0) {print $1}'
6:66893424_T_C
rs12364336
rs57502521

>=计算结果为1or 0,因此使用!=类似的方法来比较比较结果。我任意选择将零对齐为正。类似地用于==等号。

我们还可以显式定义符号函数:

$ paste file1 file2 | awk 'function sign(x) { return x >= 0 ? +1 : -1; }
                           sign($2) != sign($4) {print $1}'
6:66893424_T_C
rs12364336
rs57502521

答案3

由于awk无法对两个文件执行逐行操作,因此需要一定量的缓冲。如果您的文件足够小,它就可以工作。

awk 'NR==FNR{v[$1]=$2; next}
     {if ($2*v[$1]>=0) {print $1 > "matched"} else {print $1 > "unmatched"}}' file1.txt file2.txt
  • 读取时file1.txt,只会将“标签”-“值”对记录在数组中v,并跳到下一个输入行执行。我们是在处理file1.txt还是file2.txt通过检查每个文件行计数器是否FNR等于全局行计数器来区分NR。如果它们相等,我们正在处理第一个文件。
  • 读取时file2.txt,会检查当前行的“value”部分与对应的值的乘积是否file1.txt为零或正数。如果是,则它们的符号相等,并将“标签”部分输出到文件中matched。如果为负数,则符号不相等,“标签”部分输出到文件中unmatched

结果:

~ > cat matched 
rs151222586

~ > cat unmatched
6:66893424_T_C
rs12364336
rs57502521

笔记

  • 我假设+0-0被认为具有等号。
  • 我还假设不存在任何一个文件中第 2 列值为 0 而另一个文件中第 2 列值非零的行。

相关内容