从广泛的意义上说,氨基酸序列是一种类别特征。因而可以通过机器学习中类别特征的编码方法进行转换。常见的方法包括独热编码、目标编码等,具体可参考文章《深度盘点:类别型特征编码方法总结》。
但氨基酸序列的可能值非常多(高基类),甚至样本之间可能完全不同。因而实践中此类编码方法的效果可能有限。如笔者最近在一个免疫原性预测项目中应用hyperopt+catBoost(算法内置ordered TS编码),实验结果显示编码后的氨基酸序列特征对模型性能几乎没有影响。
氨基酸序列也可以视为文本,因而适用文本特征方法。
词袋模型:
该编码方式可以很好地应用于肽等较短序列。但是,该方法会丢失序列的顺序信息。这对于较长序列非常重要,因为许多类别是由序列中的特定结构域定义的。
# CountVectorizer: Convert a collection of text documents to a matrix of token counts
vectorizer = CountVectorizer(analyzer="char")
X_vec = vectorizer.fit_transform(X)
X_AAC = X_vec.toarray()
N-gram模型:为保留序列中的(一些)顺序信息,可以统计所有序列中最常见氨基酸组合的出现次数。
vectorizer = CountVectorizer(analyzer="char", ngram_range=(3,3), max_features = 20)
##获取20个最常见的3个字母氨基酸组合,然后统计每个组合在所有序列中的出现次数
X_train_vec = vectorizer.fit_transform(X)
X_train_AAN = X_train_vec.toarray()
embedding:首先将序列分割成氨基酸,然后为每个氨基酸分配一个编号(标记化)。
tk = Tokenizer(char_level=True)
tk.fit_on_texts(X)
seq_tok_all = tk.texts_to_sequences(X)
##for deep learning models, equal size sequences are required
max_length = 256
#max_length = len(max(X, key=len))
X_vec = pad_sequences(seq_tok_all, maxlen=max_length, padding='post')
相较一般的类别特征编码方法,基于领域先验知识的编码方法不仅能将每个氨基酸唯一映射到表征空间,还能捕获氨基酸的特定属性。
如BLOSUM可以捕获演化关系,VHSE8可以捕获理化性质。
BLOSUM62:BLOSUM62 是一个替换矩阵,通过分数来说明氨基酸之间的相似性。该分数反映了在大型蛋白质数据库中研究序列保守性时发现的替换频率。数字62指在分析中序列聚类的一致性。
import epitopepredict as ep
blosum = ep.blosum62
def blosum_encode(seq):
#encode a peptide into blosum features
s=list(seq)
x = pd.DataFrame([blosum[i] for i in seq]).reset_index(drop=True)
e = x.values.flatten()
return e
e=blosum_encode(pep)
NLF:使用许多理化特性,通过Fisher Transform(类似PCA)进行转换,从而产生一组较小的特征,这些特征同样可以很好地描述氨基酸。共有 19 个变换特征。
#read the matrix a csv file on github
nlf = pd.read_csv('https://raw.githubusercontent.com/dmnfarrell/epitopepredict/master/epitopepredict/mhcdata/NLF.csv',index_col=0)
def nlf_encode(seq):
x = pd.DataFrame([nlf[i] for i in seq]).reset_index(drop=True)
e = x.values.flatten()
return e
e=nlf_encode(pep)
VHSE8:
#https://github.com/ikmb/amino_acid_encoding_deep_learning_applications/blob/master/CustomTrainingScripts/trainAnHLARNNmodelVHSE8.py
## load the tokenizer:
with open("OneMerAminoAcidTokenizer.pickle","rb") as input_:
tokenizer=pickle.load(input_)
## load the VHSE8
raw_VHSE=pd.read_csv('VHSE8.csv')
# prepare VHSE for embedding:
VHSE=np.zeros((21,8),dtype=np.float32)
count=0
for index, char in enumerate(tokenizer.word_index):
count+=1
embedding_vector= np.array(raw_VHSE.loc[raw_VHSE.AA==char.upper()])[:,1:9].reshape(8,)
VHSE[index+1,:]=[embedding_vector[i].replace("−",'-') for i in range(embedding_vector.shape[0])]
if count ==20: # breake after getting the index of the 20th amino acid as VHSE8 only encode the standerd 20 amino acids
break
## load and Encode the train dataset:
trainData=pd.read_csv(trainDataPath)
trainlabels=np.array(trainData.iloc[:,1].tolist())
trainTensor=tf.keras.preprocessing.sequence.pad_sequences(sequences=
tokenizer.texts_to_sequences(trainData.iloc[:,0]),dtype=np.int32,
maxlen=37,padding="pre")
##...
尽管基于领域先验知识的编码方法提供了属性信息,但特定属性可能对某些任务可能并没有太大用处。因而提出了任务特异的编码方法,集直接从数据中学习编码方法。
根据的Hesham在亲和力和蛋白互作任务上的实验结果,端到端的方法可以获得不逊于先验知识的性能。
ElAbd, Hesham, et al. “Amino acid encoding for deep learning applications.” BMC bioinformatics 21 (2020): 1-14.
Create an MHC-Class I binding predictor in Python
Protein encoding for deep learning models