前言:Python强大的脚本功能为生物信息学数据处理提供了巨大的帮助,本文介绍python在序列处理中的一点点小知识,希望能对初学生信者在序列上的处理上有一定帮助。


一、文件打开

Open函数
如打开f盘下的zzj.txt 文档:f=open(r’ f:\zzj.txt’)
这行代码非常简单,也很常用,我们通常将我们要处理的序列信息保存到txt文件里。

二、读取数据

1.读取整个文本: f.read()

如:f=open(r’ c:\zzj.txt’)

2.读取一定的字符数: f.read(n)

如:f=open(r’ f:\zzj.text’)
f.read(7)

3.按行读取且按行输出

  1. f1=open(r'f:\zzj.txt')
  2. for line in f1:
  3. print line
  4. f1.close()

三. 函数split() 常用于**序列格式处理**

提问:为什么是函数split()常用?
将表格信息选中后复制粘贴到txt文件里后,原来表格里的不同列,复制后在txt文档里之间的间隔是制表符而非空格。split函数就是用来对制表符进行识别分割。
Python中有split()和os.path.split()两个函数,具体作用如下: split():拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list) os.path.split():按照路径将文件名和路径分割

(一)函数说明

1、split()函数 语法:str.split(str=””,num=string.count(str))[n]
参数说明: str:表示为分隔符,默认为空格,但是不能为空(‘’)。若字符串中没有分隔符,则把整个字符串作为列表的一个元素 num:表示分割次数。如果存在参数num,则仅分隔成 num+1 个子字符串,并且每一个子字符串可以赋给新的变量 [n]:表示选取第n个分片
注意:当使用空格作为分隔符时,对于中间为空的项会自动忽略
2、os.path.split()函数 语法:os.path.split(‘PATH’)
参数说明:
1.PATH指一个文件的全路径作为参数:
2.如果给出的是一个目录和文件名,则输出路径和文件名。
3.如果给出的是一个目录名,则输出路径和为空文件名

(二)分离字符串

string =”www.gziscas.com.cn”
1.以’.’为分隔符
print(string.split(‘.’))
[‘www’,’gziscas’, ‘com’, ‘cn’]

2.分割两次
print(string.split(‘.’,2))
[‘www’,’gziscas’, ‘com.cn’]

3.分割两次,并取序列为1的项
print(string.split(‘.’,2)[1])
gziscas

4.分割两次,并把分割后的三个部分保存到三个文件
u1, u2, u3=string.split(‘.’,2)
print(u1)—— www
print(u2)—— gziscas
print(u3)——com.cn
实例:
1.多序列比对或Blast前进行格式处理,很常用。(分割)
代码1:

  1. f1=open(r'f:\space.txt') #space.txt文件内容是3列多行,3列分别为为序列名称、编号、序列。不同列之间在txt文件里是制表符分隔开来。
  2. f2=open(r'f:\33.txt',"w") #用于储存结果的文件。
  3. for line in f1:
  4. d=f.readline()
  5. u1,u2, u3=d.split('\t',2)
  6. f2.write( ">"+u1+u2+"\n"+u3)
  7. f1.close()
  8. f2.close()


代码2:

  1. f=open(r'f:\space.txt')
  2. f2=open(r'f:\33.txt',"w")
  3. for line in f1:
  4. d=f.readline()
  5. f2.write(">"+(d.split('\t',2)[0])+(d.split('\t',2)[1])+"\n"+(d.split('\t',2)[2]))
  6. f1.close()
  7. f2.close()

效果截图如下:
Python进行常见序列处理(1) - 图1
注意点:使用前看清有几个制表符,split里面的参数要做相应调整。

FAQ: 什么是**标准的fasta格式**序列?
标准的fasta格式序列,即对于每条序列而言,序列名称占一行,序列也只占一行,比如上图。

.python如何去除重复行并分别统计重复的行数?

  1. 比如下面的重复,存在内容完全相同的行。怎么把内容重复的行只保留一行,并且统计这样内容重复的行它有多少条?<br />![](https://cdn.nlark.com/yuque/0/2018/png/119869/1538565715960-3885ebc8-f6bd-4c3c-a98d-d89ff524f5a3.png#align=left&display=inline&height=520&originHeight=520&originWidth=616&status=done&width=616)<br /> <br /> **代码如下:**
  1. a=[] #初始化要用到的列表a,用于记录原始行信息
  2. b=[] #初始化要用到的列表b,用于记录结果数据。
  3. f1=open(r'f:\1.txt') #打开1.txt文件
  4. for line in f1:
  5. a.append(line) #将1.txt文件每一行作为一个元素,存入列表a
  6. f1.close
  7. for n in a: #遍历a中每一项(记为n),即1.txt中每一行
  8. flag=1
  9. for i in range(0,len(b)):
  10. if n == b[i][0]: #n与列表b中的每一项对比,如果有相等的:
  11. b[i][1]=b[i][1]+1 #那么对应的出现计数加1
  12. flag=0
  13. break
  14. if flag==1: #如果前面的比对没有一个相等的,即该行是第一次出现:
  15. b.append([n,1]) #那么在列表b中添加改行为新的一项
  16. f2=open(r'f:\2.txt', "w") #打开2.txt文件,用于输出结果
  17. for n in b: #输出格式为:行信息(tab)出现次数 (回车)
  18. f2.write(str(n[0][0:-1]) +"\t")
  19. f2.write(str(n[1]) +"\n")
  20. f2.close
  21. print "Finished" #分析完成标记


如果不用统计个数,只需要剔除重复的行,则可以使用下面的代码:

  1. lines_seen = set()
  2. outfile = open(r"f:\2.txt","w")
  3. for line in open(r'f:\1.txt'):
  4. if line not in lines_seen:
  5. outfile.write(line)
  6. lines_seen.add(line)
  7. outfile.close()
  8. print "Finished" #分析完成标记

演示截图略。

五.如何将空字符换成制表符?

  1. 你没看错,说的就是空字符(空字符≠空格),空字符就是什么都没有。<br /> 生物信息学中,txt数据处理后有时要导入表格(EXCEL),只有字符与字符之间的制表符才可以EXCEL中分栏(分列)显示。<br /> 本人遇到过一例。将数据从表格导入txt进行批量处理时,写的代码忘记把制表符加上了,导致后来再将txt中的内容导入表格结果不能像以前一样分栏。<br />![](https://cdn.nlark.com/yuque/0/2018/png/119869/1538565810368-0e325bdf-4fcb-45c3-996c-2a067d9c44c5.png#align=left&display=inline&height=212&originHeight=212&originWidth=654&status=done&width=654)
  2. 上面的序列,标黄色(菌株名)的和标蓝色(序列号)的之间为空字符,而序列号与后面的序列之间其实不是空格,而是为制表符。<br /> 将他们复制粘贴到EXCEL表格中,黄色部分会和蓝色部分在同一列,也就是在同一个格子里,但是我们需要在EXCEL表格中把他们放在不同列显示出来,怎么办?<br /> 这种情况我们可以先对txt文件里的信息用下面代码进行补救。
  1. outfile =open(r"f:\out.txt", "w") #用作输出文件
  2. for line inopen(r'f:\1.txt'):
  3. line= line.replace('NC_','\t'+"NC_")
  4. line= line.replace('NZ_','\t'+"NZ_")
  5. outfile.write(line)
  6. outfile.close()
  7. print "Finished" #分析完成标记

上面代码其实是见招拆招。只是用到了replace函数。
这样一来,再将txt里的信息复制粘贴到EXCEL表格中时,黄色部分会和蓝色部分就在不同列了。
警告:所以将数据从表格导入txt后用代码进行某种批量处理时,一定要考虑制表符丢没丢?加不加会不会有影响?这样后期就不会有这么多麻烦事。

六.如何从字符串中提取特定字符串并输出?

Python进行常见序列处理(1) - 图2
如上图,如果想要直观地知道protospacer_description里的每一行属于噬菌体,质粒,病毒的哪一种,则可以用下面代码。

  1. outfile = open(r"f:\out.txt", "w")
  2. a="phage"
  3. b="virus"
  4. c="plasmid"
  5. for line in open(r'f:\1.txt'):
  6. if line.find(a) != -1:
  7. outfile.write(a+"\n")
  8. elif line.find(b) != -1:
  9. outfile.write(b+"\n")
  10. elif line .find(c) != -1:
  11. outfile.write(c+"\n")
  12. outfile.close()
  13. print "Finished" #分析完成标记

Python进行常见序列处理(1) - 图3

七. 统计两个文本有没有相同内容的行,并将相同的行输出

  1. 举个例子,有两个txt文件,1.txt2.txt1.txt文件里每一行是一株猪链球菌的CRISPRDR序列,2.txt文件里每一行是一株肺炎链球菌的CRISPRDR序列,现在我想知道猪链球菌的CRISPR和肺炎链球菌的CRISPR之间有没有相同的DR,相同的又是哪些DR,下面代码可以实现:
  1. c1=open(r'h:\1.txt')
  2. c2=open(r'h:\2.txt')
  3. a=[]
  4. b=[]
  5. c=""
  6. k=0
  7. for line in c1:
  8. a.append(line)
  9. c1.close
  10. for line in c2:
  11. b.append(line)
  12. c2.close
  13. for n in range(0,len(a)):
  14. for i in range(0,len(b)):
  15. if b[i]==a[n]:
  16. c+=b[i]
  17. k=k+1
  18. break
  19. print c + str(k) #输出结果并统计个数

八. 分段数据相似度比较,联合输出结果

如在一个txt文本里,有多行序列信息,而每行又由两个部分组成,DNA序列+蛋白质序列(用制表符将两种序列隔开)
现在,我想比较下每行之间的DAN序列相似度和蛋白质序列相似度,并将比对的两个结果在同一行输出,可用以下代码:

  1. import difflib #函数difflib为一种计算序列相似度的方法
  2. c1=open(r'e:\jj.txt') #jj.txt是储存序列信息的文件,每一行用制表符分成两部分(DNA序列+蛋白质序列)
  3. a=[]
  4. b=[]
  5. for line in c1:
  6. a.append(line)
  7. b.append(line)
  8. c1.close
  9. k=0
  10. for n in range(0,len(a)):
  11. for i in range(n+1,len(b)):
  12. u1, u2=a[n].split('\t',1)
  13. u3, u4=b[i].split('\t',1)
  14. C=""
  15. D=""
  16. C=difflib.SequenceMatcher(None,u1,u3).ratio()
  17. D=difflib.SequenceMatcher(None,u2,u4).ratio()
  18. print str(C)+"\t"+str(D)

示例结果如下:
Python进行常见序列处理(1) - 图4

九. 关联信息并顺序输出

现在有两个文件,3.txt里有每一行是GenID号,4.txt每一行是含有GenID号的全名称。
如下图:(注:两个截图均只展示了实际内容的一部分)
Python进行常见序列处理(1) - 图5
图1,文件内容部分截图

Python进行常见序列处理(1) - 图6
图2,文件内容部分截图

  1. 现在我想要做一件事,一件什么事呢?我想把4.txt里这样信息全面的名称通过索引关联给3.txt里的GenID,并按照3.txt里的顺序输出。<br /> 代码如下:
  1. f1=open(r"h:\3.txt") #短的名称
  2. a=[]
  3. b=[]
  4. for line1 in f1:
  5. line1=line1.strip()
  6. a.append(line1)
  7. f1.close()
  8. f2=open(r"h:\4.txt") #长的名称
  9. for line2 in f2:
  10. line2=line2.strip(" ")
  11. b.append(line2)
  12. for i in range(len(a)):
  13. flag=1
  14. s=a[i].strip()
  15. for n in range(len(b)):
  16. chang=b[n].strip()
  17. if chang[0:8]==s: #示例数据中GenID号为8个字符
  18. print b[n].strip()
  19. flag=0
  20. break
  21. if flag==1:
  22. print a[i].strip()
  23. f1.close()
  24. f2.close()


效果如下:(部分截图)
Python进行常见序列处理(1) - 图7
图3 输出结果部分截图

可以发现输出结果与3.txt里的顺序是一样的
这个到底有什么用?用处非常大,最简单用途是,比如你某个文件里的数据用的名称是GenID号,现在你想把名称给换换,但是信息比较全的名称在另外一个文件里,而且两个文件的含有相同GenID号的行的顺序不相同,你是要不断通过ctrl+F来一一查找替换还是通过几行代码来解决?
有没有想过,以上面的这样的对应索引来输出结果的代码为基础,进行改变,变成依据索引来进行批量替换?

十.去除名称重复的序列

当使用大数据批量blast的时候,我们可能匹配到一些名称(注意这个词)重复的序列,这个时候序列做去重处理,下面代码可以完成这个工作:
代码如下:

  1. seq=open(r"h:\seq.txt") #输入文件路径,该文件格式要求:每条序列,序列名称占一行,序列也只占一行的fasta格式序列。
  2. out=open(r"h:\seq-out.txt","w") #输出文件路径
  3. a=[] #建立一个空的列表a
  4. for line in seq:
  5. line=line.strip() #去掉首尾制表符、空格、换行符
  6. a.append(line) #把输入文件里的每一行都存入到列表a中,一行即一个元素
  7. n=len(a)
  8. s=""
  9. b=[] #重建用来去重的列表
  10. for i in range((n/2)): #len表示长度,对于列表a而言,len(a)表示列表a里元素的数目
  11. s=a[2*i]+"\t"+a[2*i+1]
  12. b.append(s)
  13. #以下步骤为去重
  14. lines_seen = set()
  15. c=[]
  16. for line in b:
  17. u1,u2=line.split("\t")
  18. if u1 not in lines_seen:
  19. c.append(line)
  20. lines_seen.add(u1)
  21. for line in c:
  22. u1,u2=line.split("\t")
  23. out.write(u1+"\n"+u2+"\n")
  24. seq.close()
  25. out.close()
  26. print "Finished" #分析完成标记

FAQ:如果两条序列名称是不同的,但是序列是相同的(即重复的),这种情况下怎么剔除重复序列?
答:要达到这种目的,方法请参照本文第四部分

十一.多行序列转成一行

我们下载的fasta格式的序列,每条毒(菌株)株序列可能会占多行。通过将序列文件导入诸如Mega等程序,可以将输出为序列名称占一行且序列只占一行的fasta格式的序列。
但是,当序列条数非常多且很长时,比如20000条,如果电脑运行内存较小(比如4G),Mega读取会很缓慢甚至程序卡死。
下面提供代码,将占多行的每条序列变成:一条序列只占一行。

  1. fr=open(r'h:\seq.txt', 'r') #输入文件
  2. fw=open(r'h:\out.txt', 'w') #输出文件
  3. s=""
  4. for line in fr:
  5. if line.startswith('>'): #判断字符串是否以‘>开始’
  6. line="\n"+line
  7. else:
  8. line=line.replace('\n', '')
  9. s=s+line
  10. fw.write(s)
  11. fr.close()
  12. print "Finished" #分析完成标记

十二.输出特定位点为某氨基酸的序列

将氨基酸序列进行多序列比对对齐后,如果想筛选对齐后在第i位点为某氨基(比如M氨基酸)的序列,可以通过下面代码完成。

  1. seq=open(r"h:\seq.fas") #输入文件路径,该文件格式要求为序列名称占一行,序列只占一行的fasta格式序列。
  2. out=open(r"h:\seq-out.txt","w") #输出文件路径
  3. a=[] #建立一个空的列表a
  4. for line in seq:
  5. line=line.strip()
  6. a.append(line) #把输入文件里的每一行都存入到列表a中,一行即一个元素
  7. s=""
  8. for n in range(len(a)): #len表示长度,对于列表a而言,len(a)表示列表a里元素的数目
  9. s=a[n] #把每一个元素(相当于输入文件里的每一行)的值赋给s
  10. if n % 2 == 1: #判断是否是第偶数行
  11. if s[i-1:i]=="M": #判断对齐后的第i个位点,具体i值依据实际情况来定
  12. out.write(a[n-1]+"\n"+s+"\n")
  13. seq.close()
  14. out.close()

定义子函数法:

  1. #第一步,定义子函数panbieweidian
  2. def panbieweidian (seqline,outline,i,aa):
  3. seq=open(seqline)
  4. out=open(outline,"w")
  5. a=[]
  6. for line in seq:
  7. line=line.strip()
  8. a.append(line)
  9. s=""
  10. for n in range(len(a)):
  11. s=a[n]
  12. if n % 2 == 1:
  13. if s[i-1:i]==aa:
  14. out.write(a[n-1]+"\n"+s+"\n")
  15. seq.close()
  16. out.close()
  17. #第二步,调用子函数panbieweidian
  18. panbieweidian (r"h:\seq.fas",r"h:\seq-out.fasta",10,"M") #与定义的子函数里的参数一一对应即可
  19. #上面为判断第10位是不是氨基酸M,以后只需在调用函数这里修改相应位点和氨基酸类型即可,而第一步的子函数部分不需要改动。
  20. #注意,seq.fas该输入文件格式要求为序列名称占一行,序列只占一行。
  21. #采用定义子函数的方法写代码后,对相关位点和氨基酸的判别进行修改比较方便,代码重复利用率高。

十三.利用查询功能关联信息

  1. 前面在第“九”部分提到了利用索引关联信息,很多小伙伴反映一个问题:这种方法仅仅适用于索引信息规规矩矩地出现在被关联的文本**每行的前几个字符**,而且**字符数还是固定的**。<br />那么,对于**字符数不固定**,而且**位置也不固定**的索引,怎么通过它给两个文本关联信息呢?<br />比如下面的:<br />![](https://cdn.nlark.com/yuque/0/2019/png/119869/1551449340514-e919b29c-204c-4439-b55a-34ba151db5c7.png#align=left&display=inline&height=386&originHeight=386&originWidth=469&status=done&width=469)<br />**(图1,地区经纬度信息表,部分)**

Python进行常见序列处理(1) - 图8
(图2,名称表,部分)

我想把给图2的名称表添加上来自图1的地区经纬度信息,采用下面代码find()函数可以完成任务:

  1. mingchen=open(r"h:\mingchen.txt") #名称列表文件
  2. jingwei=open(r"h:\jingwei.txt") #经纬度文件
  3. out=open(r"h:\xingxi-out.txt","w") #输出结果文件
  4. a=[]
  5. for line in jingwei:
  6. line=line.strip()
  7. a.append(line)
  8. for line in mingchen:
  9. flage=1
  10. line=line.strip()
  11. for n in range(len(a)):
  12. u1,u2=a[n].split("\t",1)
  13. if line.find(u1)!=-1:
  14. flage=0
  15. s=u2
  16. if flage==0:
  17. out.write(line+"\t"+s+"\n")
  18. elif flage==1:
  19. out.write(line+"\n")
  20. mingchen.close()
  21. jingwei.close()
  22. out.close()
  23. #经纬度表里的地区名字和名称表里的要相同。


将结果复制到Excle表里,效果如下:
Python进行常见序列处理(1) - 图9

也可以采用定义子函数的方法,如下:

  1. def jingweichaxun (inputmingchen,inputjingwei,outline):
  2. mingchen=open(inputmingchen)
  3. jingwei=open(inputjingwei)
  4. out=open(outline,"w")
  5. a=[]
  6. for line in jingwei:
  7. line=line.strip()
  8. a.append(line)
  9. for line in mingchen:
  10. flage=1
  11. line=line.strip()
  12. for n in range(len(a)):
  13. u1,u2=a[n].split("\t",1)
  14. if line.find(u1)!=-1:
  15. flage=0
  16. s=u2
  17. if flage==0:
  18. out.write(line+"\t"+s+"\n")
  19. elif flage==1:
  20. out.write(line+"\n")
  21. mingchen.close()
  22. jingwei.close()
  23. out.close()
  24. jingweichaxun (r"h:\mingchen.txt",r"h:\jingwei.txt",r"h:\xingxi-out.txt")
  25. #很明显,这个例子定义子函数并没有什么优势。

十四.依据起始位点表截取基因片段

欲截取核苷酸序列的某一片段,手上只有每条序列需要截取的起始位点表,怎么用python脚本解决?
准备材料:
文件1:待截取的基因序列,要求为标准的fasta格式,对于每条序列:序列名称占一行,序列也只占一行。
文件2:需要截取的片段起始位点表(示例如下图),先在EXCLE里做好这个表,再将信息复制到txt文档里。
注意:文件1里的序列名称和文件2里的要一致。
Python进行常见序列处理(1) - 图10

脚本:

  1. import string
  2. f1=open(r"h:\seq.fas") #上述文件1
  3. f2=open(r"h:\biaozhun.txt") #上述文件2
  4. out=open(r"h:\jiequ-out.fasta","w") #输出文件,事先不需要建立
  5. #将f1内容存入列表a,如下:
  6. a=[]
  7. for line in f1:
  8. line=line.strip() #去掉首尾制表符、空格、换行符
  9. a.append(line) #把输入文件里的每一行都存入到列表a中,一个元素表示原文件一行
  10. #重新改变序列样式,为“序列名称+制表符+序列”占一行,存入列表b,如下:
  11. n=len(a)
  12. s=""
  13. b=[]
  14. for i in range(int(n/2)):
  15. s=a[2*i]+"\t"+a[2*i+1]
  16. b.append(s)
  17. #将f2内容存入列表c,如下:
  18. c=[]
  19. for line in f2:
  20. line=line.strip()
  21. c.append(line)
  22. #依据f2里的长度限定,截取序列长度,如下:
  23. for n in range(len(b)):
  24. u1,u2=b[n].split("\t",1)
  25. u1=u1.strip()
  26. u1=u1.replace(">","")
  27. u2=u2.strip()
  28. for m in range(len(c)):
  29. mingchen,qishi,jieshu=c[m].split("\t",2)
  30. mingchen=mingchen.strip()
  31. x1 = string.atoi(qishi.strip()) #将字符转化为整数
  32. x2 = string.atoi(jieshu.strip()) ##将字符转化为整数
  33. jiequ=""
  34. if u1==mingchen:
  35. jiequ=u2[x1 - 1 : x2] #jiequ[x1 - 1 : x2]表示输出字符串jiequ的第x1个字符到第x2个字符(包括第x1和第x2)
  36. out.write(">"+u1+"\n"+jiequ+"\n")
  37. f1.close()
  38. f2.close()
  39. out.close()

用途:以冠状病毒为例,欲获取冠状病毒RdRp(RNA依赖的RNA聚合酶基因)的核苷酸序列,由于NCBI上只有氨基酸序列。
但是,RdRp基因位于冠状病毒ORF1ab内,故先将冠状病毒的ORF1ab核苷酸序列在Pfam在线工具上进行预测,得到RdRp基因的起始位点,再依据该起始位点对冠状病毒ORF1ab核苷酸序列进行截取,如上代码即可得到RdRp的核苷酸序列。

如文中有错误之处,欢迎大家及时指正,一起交流学习。