【问题标题】:Optimising my script which lookups into a big compressed file优化查找大压缩文件的脚本
【发布时间】:2020-02-22 06:33:41
【问题描述】:

我又来了!我想优化我的 bash 脚本以减少每个循环所花费的时间。 基本上它的作用是:

  • 从 tsv 获取信息
  • 使用该信息通过 awk 查找文件
  • 打印该行并将其导出

我的问题是: 1)文件是60GB的压缩文件:我需要一个软件来解压它(我现在实际上正在尝试解压它,不确定我是否有足够的空间) 2) 反正要研究很久了

我改进它的想法:

  1. 0) 如前所述,如果可能的话我会解压文件
  2. 将 GNU 与 parallel -j 0 ./extract_awk_reads_in_bam.sh ::: reads_id_and_pos.tsv 并行使用,但我不确定它是否按预期工作?我将每项研究的时间从 36 分钟缩短到 16 分钟,所以只是 2.5 倍? (我有 16 个核心)

  3. 我在想(但它可能对 GNU 来说是多余的?)拆分 我的信息列表来查看几个文件以启动它们 并行

  4. 按读取名称对 bam 文件进行排序,并在完成后退出 awk 找到 2 个匹配项(不能超过 2 个)

这是我的 bash 脚本的其余部分,我非常愿意提出改进它的想法,但我不确定我是否是编程界的超级明星,所以保持简单可能会有所帮助吗? :)

我的 bash 脚本:

#/!bin/bash
while IFS=$'\t' read -r READ_ID_WH POS_HOTSPOT; do
echo "$(date -Iseconds) read id is : ${READ_ID_WH} with position ${POS_HOTSPOT}" >> /data/bismark2/reads_done_so_far.txt
echo "$(date -Iseconds) read id is : ${READ_ID_WH} with position ${POS_HOTSPOT}"
samtools view -@ 2 /data/bismark2/aligned_on_nDNA/bamfile.bam | awk -v read_id="$READ_ID_WH" -v pos_hotspot="$POS_HOTSPOT" '$1==read_id {printf $0 "\t%s\twh_genome",pos_hotspot}'| head -2 >> /data/bismark2/export_reads_mapped.tsv
done <"$1"

我的 tsv 文件格式如下:

READ_ABCDEF\t1200

非常感谢你++

【问题讨论】:

  • 您是否考虑过用 Python 重写脚本的并行部分?我知道你可以在 bash 中实现它们,但这可能会让你的生活更简单......

标签: bash bioinformatics gnu-parallel


【解决方案1】:

TL;DR

您的新脚本将是:

#!/bin/bash
samtools view -@ 2 /data/bismark2/aligned_on_nDNA/bamfile.bam | awk -v st="$1" 'BEGIN {OFS="\t"; while (getline < st) {st_array[$1]=$2}} {if ($1 in st_array) {print $0, st_array[$1], "wh_genome"}}'

您正在读取每个输入的整个文件。最好同时查找所有这些。首先提取有趣的读取,然后在这个子集上应用第二个转换。

samtools view -@ 2 "$bam" | grep -f <(awk -F$'\t' '{print $1}' "$1") > "$sam"

在这里,您将获得所有带有samtools 的读数,并搜索出现在grep-f 参数中的所有术语。该参数是一个包含搜索输入文件第一列的文件。输出是一个 sam 文件,其中仅包含搜索输入文件中列出的读取。

awk -v st="$1" 'BEGIN {OFS="\t"; while (getline < st) {st_array[$1]=$2}} {print $0, st_array[$1], "wh_genome"}' "$sam"

最后,使用 awk 添加额外信息:

  1. 以 awk 开头打开搜索输入文件,并将其内容读入数组 (st_array)
  2. 将输出字段分隔符设置为制表符
  3. 遍历 sam 文件并添加预填充数组中的额外信息。

我提出这个模式是因为我觉得 grepawk 更快,但单独使用 awk 可以获得相同的结果:

samtools view -@ 2 "$bam" | awk -v st="$1" 'BEGIN {OFS="\t"; while (getline < st) {st_array[$1]=$2}} {if ($1 in st_array) {print $0, st_array[$1], "wh_genome"}}'

在这种情况下,您只需要添加一个条件来识别感兴趣的读取并摆脱grep

在任何情况下,您都需要多次重新读取该文件或在使用它之前对其进行解压缩。

【讨论】:

  • 嗨,它看起来很优雅,但是我在理解其中的所有内容时遇到了一些问题:) 1. 所以我应该放弃我的 bash 方法吗?我理解第一部分,它只是用匹配的行对数据集进行子集。然后 "$1" 实际上是我脚本中的 READ_ID_WH。然后我应该用while read/do/done 2为这部分做一个循环。它输出$sam,它作为awk的参数给出。在这里我不太明白:我们应该再次循环,因为我确实需要读取的全部信息,但也需要我们拥有它的位置:) 我要实现两个循环吗?谢谢+++!
  • 1.我认为你应该放弃你的 bash 方法,是的。这是非常低效的。最好使用我的 bash 方法,这将更快且所需资源更少。 $1 与您在脚本中的 $1 相同。实际上,我的命令行应该可以替代您问题中的整套命令。您不需要任何额外的 bash 循环。唯一需要的循环是在 awk 脚本内部,它用于将 tsv 文件 ($1) 的内容加载到内存中。
  • 2.您不必再次循环。 $sam 包含所有感兴趣的行,awk 脚本读取内存中的所有 tsv 文件以扩展输出信息,就像遍历子集文件一样。
  • 好的,我现在理解得更好了 :) 我只是面临将 $1 作为要读取的文件传递的问题,awk 告诉我找不到它.. 我尝试使用 -v 但是不行,我在挖!
  • 是的,在 awk 脚本中,$N 指的是第 N 个字段。可能您正在使用第一个字段作为该行的键,因此您可以将其他字段添加到其他变量:second_field[$1]=$3; third_field[$1]=$4,然后在打印命令中将它们输出到所需位置。
猜你喜欢
  • 2012-01-29
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
  • 1970-01-01
  • 2014-04-10
  • 1970-01-01
相关资源
最近更新 更多