Perl
1. 拆分FASTA文件
将FASTA文件按照用户指定的序列条数进行拆分,即每n条序列写到一个文件中,或者按照指定的输出文件数进行拆分,则每个文件中包含的序列数相同
脚本名:splitFasta.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use POSIX;
# 帮助文档
=head1 Description
This script is used to split fasta file, which is too large with thosands of sequence
=head1 Usage
$0 -i <input> -o <output_dir> [-n <seq_num_per_file>] [-m <output_file_num>]
=head1 Parameters
-i [str] Input raw fasta file
-o [str] Output file to which directory
-n [int] Sequence number per file, alternate chose paramerter "-n" or "-m", if set "-n" and "-m" at the same time, only take "-n" parameter
-m [int] Output file number (default:100)
=cut
my ($input,$output_dir,$seq_num,$file_num);
GetOptions(
"i:s"=>\$input,
"o:s"=>\$output_dir,
"n:i"=>\$seq_num,
"m:i"=>\$file_num
);
die `pod2text $0` if ((!$input) or (!$output_dir));
# 设置每个文件的序列条数
if(!defined($seq_num)){
if(!defined($file_num)){
$file_num=100;
my $total_seq_num=`awk 'BEGIN{n=0} /^>/{n++} END{print n}' $input`;
chomp $total_seq_num;
$seq_num=ceil($total_seq_num/$file_num);
}else{
my $total_seq_num=`awk 'BEGIN{n=0} /^>/{n++} END{print n}' $input`;
chomp $total_seq_num;
$seq_num=ceil($total_seq_num/$file_num);
}
}
open IN,"<$input" or die "Cann't open $input\n";
my $n_seq=0; # 该变量用于记录当前扫描到的序列数
my $n_file=1; # 该变量用于记录当前真正写入的文件的计数
my $input_base=`basename $input`;
chomp $input_base;
open OUT,">$output_dir/${input_base}_${n_file}" or die "Cann't create $output_dir/${input_base}_${n_file}\n";
while(<IN>){
next if (/^\s+$/); # 跳过空行
chomp;
if (/^>/){
$n_seq++;
# 判断目前已经扫描到的序列数,若大于设定的split的序列数,则创建新文件
if ($n_seq>$seq_num){
$n_seq=1;
$n_file++;
close OUT;
open OUT,">$output_dir/${input_base}_${n_file}" or die "Cann't create $output_dir/${input_base}_${n_file}\n";
print OUT "$_\n";
}else{
print OUT "$_\n";
}
}else{
print OUT "$_\n";
}
}
close IN;
执行方法:
1 | $ perl splitFasta.pl -i <input> -o <output_dir> [-n <seq_num_per_file>] [-m <output_file_num>] |
具体的参数使用说明可以执行 perl splitFasta.pl
,查看脚本使用文档
2. 从双端FASTQ文件中抽取指定数据量(bp)的序列
按照用户指定的数据量,即多少bp,从原始的双端FASTQ文件中随机抽取序列,要求双端FASTQ文件中的序列必须配对
脚本名:extractFastq.pl
1 | #!/usr/bin/perl |
执行方法:
1 | $ perl extractFastq.pl -n <totalReads> -e <base-pairs to extract> -l <readLength> -1 <input1.fastq> -2 <input2.fastq> [-o <outdir>] |
具体的参数使用说明可以执行 perl extractFastq.pl
,查看脚本使用文档
3. 双端FASTQ文件进行双端配对
脚本名:PairsMate.pl
1 | #!/usr/bin/perl |
执行方法:
1 | $ perl PairsMate.pl -1 <input1.fastq> -2 <input2.fastq> [-o <outdir>] |
具体的参数使用说明可以执行 perl PairsMate.pl
,查看脚本使用文档
4. 根据序列Id提取FASTA序列
提供FASTA文件,和包含序列Id的文件(有多列,用制表符隔开,其中一列为序列Id),提取该序列Id对应的FASTA序列
脚本名:extractSeqFromFasta.pl
1 | #!/usr/bin/perl |
使用方法:
1 | $ perl extractSeqFromFasta.pl <in.fasta> <gene list> <out.fasta> |
5. 统计FastQC输出
统计FastQC结果,注意脚本需要在FastQC输出结果所在目录下运行。脚本的统计项目及输出如下:
Sample | Total Reads | GC Content | Q20 | Q30 |
---|---|---|---|---|
NP006_RRS05401_1.clean.fq.extract_fastqc | 39998924 | 49 | 0.999430935 | 0.946251454 |
NP006_RRS05401_2.clean.fq.extract_fastqc | 39998924 | 49 | 0.986292131 | 0.883245809 |
NP007_RRS05402_1.clean.fq.extract_fastqc | 40003323 | 49 | 0.999429311 | 0.946197936 |
脚本名:fastqc_stat.pl
1 | opendir (DIR, "./") or die "can't open the directory!"; |
执行方法:
1 | $ perl fastqc_stat.pl |
Python
1. 格式化FASTA文件
在规范的Fasta文件中,你看到的一条序列记录包括两部分:
- 以
>
起始的序列名称,占一行; - 由核苷酸ATCGN(核酸序列)或氨基酸字符组成的字符串,一般每60个字符一行,若一条序列很长,那么它可能会占多行;
有的时候因为一些原因(一般都是自己在上游分析时图方便生成的)你得到的fasta文件中的序列部分没有按照60个字符一行的形式进行组织,而是将整条序列放在一行里,虽然一般来说这并不会对你的分析产生太大的影响,但是进行查看的时候会有一些不方便,比如
这个时候如果想将它调整组成规范的格式,要怎么实现呢?
用BioPython将原始FASTA文件读入,然后在写出,就能得到你想要的效果
这个脚本很简单,只有四行代码
脚本名:formatFasta.py
1 | from Bio import SeqIO |
用法:
1 | $ python formatFasta.py <in.fa> <out.fa> |
R
1. 合并多个样本的定量结果成一个大矩阵 (profile matrix)
在RNAseq或者metagenome shotgun中,需要对每个样本进行逐一定量,生成每个样本各种的定量结果,然后需要合并每个样本的定量结果,形成一个包含所有样本定量的profile matrix
我们这个脚本的要实现的就是合并多个样本的定量结果成一个大矩阵 (profile matrix)
实现思路:
想要保证所有样本的定量结果文件都保存在一个文件夹下,且每个文件的命名形式为:
sample+suffix
,即样本名+固定后缀
;每个文件中只有两列信息,第一列为feature(对于RNAseq,它的feature是gene或transcript;对于metagenome shotgun,它的feature是各个物种分类层级),第二列是定量结果(quant,对于RNAseq,它的定量可以是reads count、FPKM/RPKM、TPM等;对于metagenome shotgun,它的定量一般是一个取值在[0,1]的比例值);
根据指定的文件夹(下面记作
dir
)和文件后缀(下面记作pattern
),将文件路径为dir/*pattern
的文件逐一读入,获取它们的第一列,即features的列表,从而得到total unique features的列表,同时记下样本列表(样本名为:文件名-pattern
);根据上一步得到的total unique features列表和样本列表,创建一个行数等于total unique features列表长度,列数等于样本列表的矩阵(记作$\text{MergeMatrix}_{ij}$,i表示$\text{feature}_i$,j表示$\text{sample}^j$),行名对应total unique features列表,列名对应样本列表,矩阵中每个元素的值初始化为0;
再一次将文件路径为
dir/*pattern
的文件逐一读入,更新MergeMatrix对应列的值:若当前读入的文件名为sample_j.pattern
,则当前样本为$\text{sample}^j$,则根据$\text{MergeMatrix}_{ij}=\text{sample}i^j$,对矩阵$\text{MergeMatrix}{ij}$进行更新;
脚本名:Merge2ProfileMatrix.R
1 | loadMatrix <- function(dir,pattern){ |
该脚本只定义了一个函数,可以在R交互模式下,载人这个脚本中的函数,然后调用它,或者直接对这个脚本进行修改,然后用Rscript
直接执行修改后的脚本
2. 对profiles进行wilcox检验(并行化)
1 | # 四个参数,按顺序分别为: |
3. 对差异显著的subprofile进行可视化——箱线图与热图
想法:
从上游的分析中得到两种样本profile的差异统计检验结果,其中有p-value和p-adjust,可以根据p-value或p-adjust设置阈值,筛选出有统计学显著性的差异observation
根据这些observation的Id从原始profile中将这些差异observation的部分提取了得到subprofile
对subprofile进行可视化——箱线图(boxplot)与热图(heatmap)
需要提供的输入:
上游的分析中得到两种样本profile的差异统计检验结果
原始profile
样本的分组信息
脚本名:plotDiffSubprofile.R
1 | # 实现功能说明:导入差异分析的结果与原始profile,提取原始profile中提取 |
4. 对大矩阵计算Jaccard Index(并行化+分治)
在对一个大矩阵执行相关性计算或Jaccard Index的计算时,其实执行的是矩阵任意两行(这里假设要进行分析的对象是矩阵的每个行)之间的两两的计算,若这个矩阵的规模非常庞大,有n行时,计算的时间复杂度就是$O(n^2)$,这个时候可以采用并行化策略来加速这个进程(参考上文的 2. R中的并行化方法):
1 | StatOut <- parApply(cl, data, 1, fun, data) |
这样就会实现将一个 n vs. n
的问题拆分成 n 个可以并行解决的 1 vs. n
的问题,当然通过设置线程数为$m,\,(m\le n)$,使得每次只并行执行m个 1 vs. n
的问题
然后再在函数fun
内部再定义一个并行化计算来进一步并行化加速上面产生的 1 vs. n
的计算:
1 | fun <- function(vec, data){ |
在这个函数内部实现了将一个 1 vs. n
的问题拆分成 n 个可以并行解决的 1 vs. 1
的问题
这样就实现了两步并行化,这样在保证硬件条件满足的情况下,的确能显著加快分析速度
但是并行化技术会带来一个问题是,虽然时间开销减少了,但是空间开销显著增加了
比如,第一次并行化,将一个
n vs. n
的问题拆分成 $\frac{n}{m}$ 次可以并行解决的 m个1 vs. n
的问题,则需要在每一次并行化任务中拷贝一个1 vs. n
的计算对象,即原始有n行的矩阵被拷贝了m次,则相应的缓存空间也增加了m倍,很显然内存的占用大大增加了
空间开销显著增加带来的后果就是,很容易导致运行内存不足程序运行中断的问题,那该怎么解决这个问题呢?
可以采用分治方法(Divide-Conquer),将原始大矩阵,按照行拆分成多个小的子块,对每个子块执行计算,从而得到每个子块的运算结果,最后再讲每个子块的结果进行合并:
脚本名:JaccardIndex.R
1 |
|
5. 合并两个矩阵
在什么情节下,我们需要合并两个矩阵?
对于两个批次的数据,我们分别用上面 1. 合并多个样本的定量结果成一个大矩阵 (profile matrix)得到了两个profile matrix,这两个matrix的行表示feature,列表示sample,样本一般不会有重复,而features大部分是重叠的,也有少部分是不重叠的,那么将这两个矩阵合并之后,这个新矩阵的行数为两个矩阵features的并集的大小,列数为两个矩阵列数的和
脚本名:MergeTwoMat.R
1 | Args <- commandArgs(T) |
用法:
1 | $ Rscript MergeTwoMat.R <matrix1> <matrix2> |