Overview
我在之前写的一篇博客中谈到整理那些混乱的数据源,发现有pssm fts
文件夹中的子文件夹和文件并不清楚来龙去脉,这个问题困扰了我一段时间。最近在研究PSSM
算法时,与Chris
交流了一下,恍然大悟:这个文件夹中的t3pssm,t4pssm,t6pssm
三个子文件夹中的形如t6_12.pssm
的文件族,是由t3,t4,t6
这三个文件夹中的形如t6_12.fasta
的文件族经过BLAST
或者PSI-BLAST
等算法程序处理过后得到的数据。并且t3pssm,t4pssm,t6pssm
三个子文件夹中的每个子文件中包含有两个矩阵,其中第一个即为我们在构建PSSM的步骤中提到的PSSM
。这些PSSM
将会在下一步特征提取的过程中做为比对(alignment
)的模板。
由于并未拿到BLAST
和PSI-BLAST
程序的源码,所以这里只介绍从PSSM
开始到提取特征的步骤。
1.Python
编程方案
我们的项目在提取特征这一阶段的第六个步骤中,运用的就是这个PSSM
方法,这一步只有一个Linux
命令
python t34pssm.py T4undrsmp.txt ./t4 ./t4pssm
其中,t34pssm
这个Python
文件调用了另一个Python
文件pssm_ft.py
,这两个文件是用来计算提取特征的;T4undrsmp.txt
是输入文件,即被处理数据源;./t4
和./t4pssm
是两个文件夹。
下面我们详细解析这个Python
编程方案的每一步的代码和作用。在解析每一步的输出时,我在原代码的基础上引入了一个time
包
import time
这个包提供给我们一个很好的函数sleep()
,这个函数输入的数基本时间单位为秒。这样我们在遇到大量循环的时候,可以在循环体内加上这么一句:
time.sleep(1)
print #所需要的打印内容
就可以观察每一步循环的输出内容了,睡眠时间可以根据需要调整,十分方便。在终止循环时,可以在命令行界面按下ctrl+c
停止进程,这样就能记录下输出内容了。
1.1 解析t34pssm.py
文件
引入相关的包:
import fileinput
import sys
from os import listdir
from os.path import isfile, join
import re
from pssm_ft import * #引入pssm_ft.py文件
import time
读取输入参数[1]
和[2]
:
smplfasta = sys.argv[1] #T4undrsmp.txt
spfasta = sys.argv[2] #./t4
check_head = re.compile(r'\>') #正则表达式匹配符号>
有一点需要说明:由于T4undrsmp.txt
这个文件中原有的数据量太大,故输出量太大,耗时太大,我们仅取其第一条蛋白质序列作为例子说明这个算法的运算过程。第一条蛋白质序列如下:
>lpn:lpg0012 hypothetical protein (A)|1
MNTTEHTELGNGLLMDKIEGNPYLRIDEFGVLHLRLQRFGENNLPEPMELEMSAGEIIAMAGDYFTQANW
TMDLDLPKCELFNSPAELGKHLIRKPIDPKEENALITAYNNLAAPDVTRKEIDRIYSINNANYVPFSPTL
NFYAQQLMYYFRVKDYGEMLVRNQTHFTPWSIRVYILGHAIALRYARLSYELKQLATDRNYQSDNPDLST
LKISLQNKNETLSSNTLLDLANRYHAQAYSIELFTFHYYSDHFATGHMSMIGDLRVVLKERFGVWGNILA
NNLHDEVNRVGVYTVRPYDPTPNTTEAPSRARGDGKFDTCLNQFNRLACLNGMTASLKDINQVLSGGVIP
EQKKFGGLVHMPDVDFNSRQHQPLLVLSKGKVYYRNNLSQIHIISPSEYEALRENPEKHGYKELTSKWAA
FKLVTKLRLFPYLYDGSVMPVSDEKLAEIIADEKRRNPQRAPIPTPSCLPESEPTVFDWRTKASWRNNKD
SLDILDGLKKHSILAAKQTHSAIQEEEEVRLNLGV
从T4undrsmp.txt
文件中读取undersample fasta
格式的蛋白质序列:
smplist = [] #存储蛋白质序列的名称序号信息
smpcnt = 0 #记录读取的蛋白质数量
for line, strin in enumerate(fileinput.input(smplfasta)):
if check_head.match(strin):
smplist.append(strin.strip())
#print smplist #['>lpn:lpg0012 hypothetical protein (A)|1']
#time.sleep(1) #休眠一秒以观察输出
smpcnt += 1
读取1232
个fasta
格式的文件:
onlyfiles = [ f for f in listdir(spfasta) if isfile(join(spfasta,f)) ]
#print onlyfiles
#输出t4_1.fasta等1232个文件的列表,['t4_961.fasta', 't4_456.fasta', 't4_1179.fasta',……, 't4_954.fasta', 't4_567.fasta']
onlyfiles.remove('.DS_Store') #移除干扰项
将蛋白质名和文件名对应起来:
fastaDict = {} #存储“蛋白质名:文件名”的键值对
for fi in onlyfiles:
cntnt = ''
for line, strin in enumerate(fileinput.input(spfasta+'/'+fi)):
if line == 0:
cntnt += strin.strip() #去除前后空格
if cntnt in fastaDict: #检查否重复(已经存在)
print strin #打印重复(已经存在)
fastaDict[cntnt] = fi #生成键值对
print fastaDict #{'>lpn:lpg0012 hypothetical protein (A)|1': 't4_1.fasta',……,'>gi|148360344|ref|YP_001251551.1| hypothetical protein LPC_2282 [Legionella pneumophila str. Corby]|-1': 't4_580.fasta'} 一共1232个键值对
读取输入参数[3]
:
pssmdir = sys.argv[3] #PSSM模板文件目录
finalist = [] #存储PSSM文件名字的列表
for smp in smplist:
#print fastaDict[smp] #t4_1.fasta
finalist.append(pssmdir+'/'+fastaDict[smp].split('.')[0]+'.pssm') #根据fasta文件的名字找出对应的PSSM文件,输出t4_1.pssm
#print finalist #['./t4pssm/t4_1.pssm']
for fi in finalist: #读取PSSM文件列表
pssm(fi, 't4pssm.txt') #调用函数文件pssm_ft.py中的pssm(fi,output)函数
调用函数pssm(fi,output)
这一步表明真正计算的步骤将要开始,且是t4pssm.txt
和PSSM
之间的运算,与其他文件无关,更印证了我们最初的想法。
1.2 解析pssm_ft.py
文件
这个pssm_ft.py
文件的作用就是Retrieve PSSM features
,也就是检索PSSM
特征。将T4undrsmp.txt
这个文件中的序列跟PSSM
进行比对,得出蛋白质序列的特征向量。
引入相关的包:
import sys
import numpy as np
import math
import re
import fileinput
import time
numpy
这个包是用来处理大型矩阵运算的。
既然pssm(fi,output)
这个函数首先被调用,我们就先分析一下它。
def pssm(fi,output): #pssm(fi, 't4pssm.txt') fi==./t4pssm/t4_1.pssm
Amino_vec = "ARNDCQEGHILKMFPSTWYV" #20个基本氨基酸
PSSM = [] #存储PSSM的特征向量矩阵
ACC = [ [0.0] * 20 ] * 20
seq_cn = 0
for line, strin in enumerate(fileinput.input(fi)):
if line > 2:
str_vec = strin.split()[1:22] #切片截取该行的第1个至第21个字符存入向量str_vec中
#print str_vec #['M', '-2', '-3', '-4', '-5', '-3', '-2', '-4', '-4', '-3', '0', '3', '-3', '8', '-1', '-4', '-3', '-2', '-3', '-2', '0']等525个向量
if len(str_vec) == 0:
break
PSSM.append(map(int, str_vec[1:])) #将每个向量中的氨基酸符号去掉,其他字符转换为int类型,并全部存入PSSM特征向量矩阵
seq_cn += 1 #525
ACC[Amino_vec.index(str_vec[0])] = map(sum, zip(map(int, str_vec[1:]), ACC[Amino_vec.index(str_vec[0])])) #这句最长,从赋值号(=)右边开始逐步分析
"""
1. Amino_vec.index(str_vec[0]) 返回本行氨基酸符号在Amino_vec中的位置
2. ACC[Amino_vec.index(str_vec[0])] 初始值均为20维向量[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
3. map(int, str_vec[1:]) 将每个向量中的氨基酸符号去掉,其他字符转换为int类型
4. zip(map(int, str_vec[1:]), ACC[Amino_vec.index(str_vec[0])]) 返回一个tuple列表,形如[(-2,0.0),(-3,0.0),……,(-2,0.0),(0,0.0)]
5. map(sum, zip(map(int, str_vec[1:]), ACC[Amino_vec.index(str_vec[0])])) 将tuple列表中各元素转换为sum类型,即求和
6. 循环迭代,最后ACC(20维)为:
[[85.0, -27.0, -42.0, -58.0, -59.0, -14.0, -15.0, -25.0, -46.0, -53.0, -55.0, -20.0, -32.0, -75.0, -32.0, 10.0, -17.0, -88.0, -57.0, -28.0], [-23.0, 90.0, -3.0, -15.0, -80.0, 24.0, -3.0, -52.0, -10.0, -45.0, -42.0, 19.0, -31.0, -63.0, -44.0, -17.0, -10.0, -68.0, -32.0, -48.0], …… , [-5.0, -33.0, -36.0, -34.0, -36.0, -30.0, -26.0, -58.0, -49.0, 23.0, 11.0, -19.0, -12.0, -36.0, -36.0, -31.0, -5.0, -72.0, -35.0, 42.0]]
"""
fileinput.close()
ACC_np = np.array(ACC) #转换成数组
ACC_np = np.divide(ACC_np, seq_cn) #将每一个元素除以525
amcnt_max = np.amax(ACC_np) #找出最大的元素0.28380952381
amcnt_min = np.amin(ACC_np) ##找出最小的元素-0.274285714286
vfunc = np.vectorize(scale) #矢量化scale函数
"""
numpy中的vectorize函数可以将scale函数转换成可以接受向量参数的函数
"""
ACC_np = vfunc(ACC_np, amcnt_max,amcnt_min) #调用scale函数,将矩阵范围控制在[-1,1]之间
ACC_shp = np.shape(ACC_np) #(20,20)
PSSM = np.array(PSSM)
PSSM_AC = pssm_ac_cal(PSSM, GROUP, seq_cn) #调用函数pssm_ac_cal(PSSM, g, l)
"""
pssm_ac_cal(PSSM, g, l)函数,三个参数:1.PSSM矩阵;2.10;3.蛋白质序列长度
返回10×20的矩阵PSSM_AC
"""
PSSM_shp = np.shape(PSSM_AC) #(10, 20)
file_out = file(output,'a') #打开文件t4pssm.txt,如果没有则创建一个;a表示add,以追加的方式打开
np.savetxt(file_out, [np.concatenate((np.reshape(ACC_np, (ACC_shp[0] * ACC_shp[1], )), np.reshape(PSSM_AC, (PSSM_shp[0] * PSSM_shp[1], ))))], delimiter=",") #这句虽然比较长,但是逻辑比较简单清晰
"""
1. reshape函数将矩阵的行、列、维重新调整为200×1的矩阵.
2. concatenate函数将两个矩阵连接起来成为一个新矩阵.
3. savetxt函数将矩阵保存为txt格式文件,分隔符为",".
"""
现在看一下另外两个函数scale
和pssm_ac_cal
。
scale
函数:
def scale(x, max, min):
"""
把矩阵中最大的数和最小的数变为1和-1,其他数按以下比例缩放
"""
try:
return -(1-(x-min)/(max-min))+((x-min)/(max-min))
except Exception:
print "ZeroDivisionError, max-min:\s", max-min
pssm_ac_cal
函数:
def pssm_ac_cal(PSSM, g, l):
"""
输入PSSM、GROUP、蛋白质序列的长度,返回GROUP×20的PSSM_AC矩阵
"""
PSSM_AC = np.array([ [0.0] * 20 ] * g)
for pg in range(g):
l_g = l - pg - 1
for pj in range(20):
sum_jl = 0.0
for i in range(l):
sum_jl += PSSM[i][pj]
sum_jl /= l
pssm_acjg = 0.0
for i in range(l_g):
pssm_acjg += (PSSM[i][pj]-sum_jl) * (PSSM[i+pg+1][pj]-sum_jl)
pssm_acjg /= l_g
PSSM_AC[pg][pj] = pssm_acjg
return PSSM_AC
至此,Python
编程方案已解析完毕。疏漏之处请与我们联系,一定尽快修改。