统计生物信息学

为什么要学编程?

2019-01-10  本文已影响178人  刘小泽

刘小泽写于19.1.8-1.10 这部分内容学自《Perl在生物信息学中应用》

其实之前我也一直困惑这个问题?“为什么一定要自己学习编程,那么多写好的工具,直接拿来用不是更方便吗?我们毕竟是攻城狮而不是程序猿。”我如是安慰自己。

但所有的事情都有一样的规律,现在认为不重要,只是因为还没到那个程度。的确,开始我也想学编程python、perl的书也准备了,但却一直用不上知识,于是就产生了间断期。最近,有强烈的需求想要自己去探索数据的时候,却有点摸不着头脑了,因为现成的工具并不能满足我的全部需求,而且大脑里已经想象出了怎么去一步步处理,就是做不出来。这一次,我真的好想学习一下编程技术,不要求造多好的轮子,只要求自己用到的时候,有想法,能实现,就够了。之后的事情,就要等到再进阶,再有需求的情况去做了。

Perl和Python之间,我先选择Perl

这二者都很好,但是精力有限,只想先看懂简单的代码流程,另外perl one-line命令一直吸引着我,想借此机会探究一下,伊现富老师(https://github.com/Yixf-Education)翻译过一本Perl的书籍《Perl语言在生物信息学中的应用—基础篇》。三天的时间看完了这本书,记录下个人认为重点的一些地方,里面有许多知识需要不断揣摩

什么是编程语言?

指定一系列语法规则指导计算机运行,编写的程序叫源代码,需要翻译成机器语言才能让计算机识别运行。机器语言是二进制,难以肉眼读取编写,因此还需要解释器(编译器)才能运行某种编程语言写的程序(如perl解释器运行perl程序)

编程过程

例如:我们手头有一个DNA序列想看下其中的调控元件数目,大脑中的想法框架应该这样构建:

伪代码帮记录

灵感最重要,先将整体思路用语言先写出来。还是上面例子,我们可以这样写

get the name of DNA file

read in the DNA file

for each regulatory element
    if element in DNA, then
        add one to the count
print count

之后伪代码可以变成注释信息,方便自己一步步去写需要的代码,并且方便交流


常用元素


有用的操作

连接

替换--s///

image.png

注意到=~,它是绑定操作符,就是将右边的操作应用到左边变量的字符串上;

然后s/T/U/g,s表示替换(substitution),第一个斜线后跟着T,表示字符串中被替换的元素;第二个斜线后跟着U,是要替换成的元素;g表示全局

因此,这句命令的意思就是:把$RNA变量存储的字符串数据中所有T变成U

另外,如果要删除换行符或者空格或制表符,使用$RNA =~ s/\s//g

反转数组--reverse

reverse @bases ,例如:

@bases = ('A', 'C', 'G', 'T');
@reverse = reverse @bases;
print "@reverse\n\n";
# T G C A

互补--tr

tr 其实也是替换的作用,但是对于求序列的互补比较方便,第一个斜线后是要被替换的内容;第二个斜线后是替换后的内容,且位置对应进行替换

image.png

因为tr函数会返回在字符串中找到特定字符的数目,而且即使替换字符集为空,原始字符集也不会改变,因此还可以作为计数器,如:$base = ($dna =~ tr/ACGTacgt//);就可以统计所有碱基数

获取长度--scalar

scalar @bases ,对于上面的例子,得到的结果就是4

任意位置插入--splice

splice ,例如:

@bases = ('A', 'C', 'G', 'T');
splice ( @bases, 2, 0, 'X' );
print "@bases\n";
# A C X G T

参考:http://blog.sina.com.cn/s/blog_4d3a41f40100m29m.html

拆解--split

@DNA=split('',$DNA) 将$DNA拆解成单个字符的@DNA数组【与join相反】

取子集--substr

$base = substr($DNA, $position,1)

变量初始化

声明变量后需要赋一个值,如果不进行初始化,它的值将被定义为'undef',对于undef,在数字操作中表示0,在字符串操作中表示空字符串

循环

排序

范围操作符

(1../comments/) and next; ,其中(..) 是范围操作符,表示跳过第一行到包含comments的所有行。然后and是一个逻辑操作符,表示跳过后继续进行

逻辑操作符

and可以用&&表示,or 可以用|| 表示,not!表示

用逻辑操作符来控制流程:比如打开文件

open (FH, $filename) or die "Cannot open file $filename: $!";

快速调用匹配值

# 例如:'123456' =~ /34/ 可以匹配成功
$&就表示匹配上的内容'34'
$`表示匹配成功前面的内容'12'
$'表示匹配成功后面的内容'56'

正则表达

要想在正则表达式中体现//,可以用/\/\/\n/ ,但总感觉有点奇怪,像这种情况,可以在前面使用m,利用其它的界定符(一般我们使用/,但并不代表只有这一种界定方式),从而避免在正斜线前使用转义符,如m!//\n!

模式修饰

常用的模式修饰符:用于全局匹配的/g,不分区大小写的/i,将整个字符串当成单独一行的/s(忽略换行符),将整个字符串作为含有换行符的行/m/m可以让元字符^和$ 匹配嵌在内部换行符之前和之后的位置)

搭配元字符^锚定开头,$锚定结尾,.匹配除了换行符以外的任意字符

例如:要对AAC\nGTT 进行匹配

use warnings;
"AAC\nGTT" =~ /^.*$/; #使用^.*$可以匹配除了换行符外的任意字符
print $&, "\n";
# 结果报错

# 原因就在于:在中间出现了一个换行符,默认的模式修饰不能识别,因此可以转换成m修饰,会从字符串开头一直匹配到第一个换行符(即便出现在内部)
"AAC\nGTT" =~ /^.*$/m;
print $&, "\n";
#结果输出AAC,$&就是匹配到的内容

# 如果用/s,就可以匹配包括换行符在内的所有
"AAC\nGTT" =~ /^.*$/s;
print $&, "\n";
# AAC
# GTT

输出


子程序

子程序可以重复使用,可以单独进行测试,子程序本身可以调用其他子程序,总而言之,子程序就是只做一件事并把它做好,然后我们要做的就是:组合它们来完成整个任务

编写子程序示例

子程序一般包括:sub、子程序名字、大括号代码块

子程序从@_ 数组中收集参数值,然后赋给子程序的变量(子程序的变量名可以和主程序重名,并不冲突)。如果只在子程序中写my ($dna)而不加= @_,那么子程序就会使用主程序的同名变量或者报错找不到新变量

sub addbase {
    my ($dna) = @_; #perl的特殊数组是“_”。my用来声明一个新变量,只在包裹的代码块中有效
    $dna .= 'ATGC';
    return $dna
}

切记:子程序中定义任何变量,都要使用my ,可以在程序开始添加use strict; 提醒我们使用my定义变量

例如:计算DNA中G的数目

#!/usr/bin/perl -w
use strict; #强制声明变量

# 主程序
# 定义变量USAGE作为程序帮助文档,其中包含所有命令行参数[这里包括了$0和DNA]
# $0也是特殊变量,表示这个perl脚本名;DNA指的是需要的DNA序列
my ($USAGE) = "USAGE:$0 DNA\n\n"
# 数组变量@ARGV是内置变量,其中包含输入的参数;如果没有输入参数就打印程序帮助文档USAGE
unless (@ARGV){
    print $USAGE;
    exit;
}
my ($dna) =$ARGV[0]; #提取数组第一个元素,注意要换成$提取(perl的坐标从0开始)
my ($sum_Gs) = countG($dna);
print "\nThe DNA $dna has $sum_Gs G\'s in it!\n\n";
exit;

#子程序
sub countG{
    my ($dna) = @_;
    my ($count) = 0;
    $count = ($dna =~ tr/Gg//);
    return $count;
}

传递数据给子程序

重复使用的子程序—模块/库

子程序确实很方便,但是一些比较好的子程序需要应用到许多脚本中,一旦需要修改就需要修改所有脚本中的子程序,这是非常麻烦的。因此,如果一开始将子程序放到一个方便使用的文件中,如果改动就只改一次,然后可以应用到所有的脚本就好了。因此,模块(库)就诞生了。

例如,我们有一个库叫beginperl.pm(后缀名是perl module的意思),里面存放了所有的子程序。【需要注意的是,.pm文件的最后一行要是1;】。

使用库的时候,直接使用use beginperl; 【注意:这条语句放在靠近use strict;的地方;库的名字不带后缀;库如果和脚本不在一个目录下,需要绝对路径】

例如:File::Find模块帮助定位文件和目录,找到一个好的模块可以减少编程时间


应用

一:提取Genbank序列和注释信息

先对Genbank的信息分布有个大体了解,比如序列信息在最后,从ORIGIN开始到最后一行的//,注释信息是ORIGIN之前的信息

基本思路:加载文件=》遍历数组(文件每一行)=》先匹配// 得到最后一行行号=》再匹配ORIGIN得到分界线行号【之所以先匹配//是因为如果先匹配分界线的话,一旦匹配上就不会再继续进行了,也就得不到最后一行的行号了】=》序列就是ORIGIN行向下,注释就是ORIGIN行向上

#前提得到Genbank文件@Genbankfile
#sub open_file
#   given the filename, return the filehandle
sub open_file {
    my ($filename) = @_;
    my $fh;
    unless (open($fh, $filename)){
        print "cannot open\n";
        exit;
    }
    return $fh;
}
# 这里只是列一个基本思路
my $linenumber = 0;
my $end;
my $origin;
foreach my $line (@Genbankfile){
    if ($line =~ /^//\n/) {
        $end = $linenumber;
        last;
    }elsif ($line =~ /^ORIGIN/){
        $origin = $linenumber;
    }
    $linenumber++;
}
@annotation = @Genbankfile[0..($origin-1)];
@seq=@Genbankfile[($origin+1)..($end-1)];

关于读取文件:可以在命令行给出要打开的文件名(例如perl a.txt test.pl ),并在perl脚本中第一行使用<>就可以表示读取文件,例如while (<>) {操作}

二、Blast

非编程相关内容

不论是网页还是本地运行的blast,都是基于字符串匹配程序,利用字符串匹配来查找相似,来作为同源的一个指标。相似度(similarity)可以用percent identity来衡量,就是说查询的序列和数据库中的某个序列对应区域完全匹配的碱基数目,它会找到等价密码子或者不改变蛋白功能并具有相似属性的氨基酸残基之间的匹配,表示一个保守的程度。说到序列同源(homology) ,它是指序列在进化上相关,要么同源,要么不同源,没有同源度这种说法

Blast的运行主要基于:原始值S、打分算法、数据库属性。原始值(Raw score S)是对相似性和匹配大小的度量。另外在Blast的结果中还能看到:按照E值排序的hits数。一个匹配的E值/期望值(E value/Expect value)表示一个随机生成的具有同样大小和数据库构成的字符串匹配几率(其中允许空位存在)。E越接近0,表示越不可能随机发生。因此,E越小,匹配结果越好 。一般E小于1是一个比较可靠的结果

资料:

http://barc.wi.mit.edu/education/bioinfo2003/perl_bioinfo.html

https://github.com/Yixf-Education/course_Perl/tree/master/book


欢迎关注我们的公众号~_~  
我们是两个农转生信的小硕,打造生信星球,想让它成为一个不拽术语、通俗易懂的生信知识平台。需要帮助或提出意见请后台留言或发送邮件到Bioplanet520@outlook.com

Welcome to our bioinfoplanet!
上一篇下一篇

猜你喜欢

热点阅读