我正在尝试开发一个使用LinearSVC和另一个使用卷积神经网络的机器学习算法来分类DNA序列。我不得不对DNA序列进行独热编码,然后将每个序列的生成数组存储在一个列表中。但是在进行训练-测试分割步骤时,我无法使用它。
我的DNA序列是这样的(这不是我的真实数据集,只是为了举例说明。所有序列都在文件’seqs_for_test.fasta’中):
>TE_seq1 CCATAAACTATCTAAATAAGCACTTTTCTGGCTCTCTGGCCCCCCTTCTTCTTTTTGGGAAGGTGACAG AGGGTAAAAGGGCTCTCTGCCGTGCGAGGCTCCTCACAGACACACAGCAAGAAAGAAGCGCCGCGCAGCA
>TE_seq2 GATAGCCCCTCTCCCAGCCCCAGTCTGATCCCTAACCCTAACTCCACGGCTCCTGTCTCTACCCCCGTCT CTTTCTTCTTGTACCCTAGTCCCCCAGATCATTAGCTCCCTGCTCGGGCCCAGGGTTTTAAGAGAAGCCC
>TE_seq3 TGACTCAAGTCATGCTACCCAGCCCCGTCTTCTTAAAAATGAGACATGTTGAGACACCCTGCTTTTCGCC TACAAACACATCCATTCTCTATACTTAGTCTTATTTAAATTCTATCCTCTGTATGTCTAGTCCTGGGGGT
>RD_seq4 TGCTCGCCCCCCAGGAAGTGCAGAGACCGCCTGGGTGTGACTGTTTTTAGGCCTAACAAAGGCACAGAAA CACCCGTGCGGTCTCTGTATCCCCTGGAGGTATTTCTCCCCATTAGTTTGCTTGACACTAAGTTTTTAAA
>RD_seq5 TAAAAAAAGCTTATTAAGTCCCTAGAACCTGGGACCTATCTACCCAAGTTTTAAAACCTTACTTTTAAGG CTACATTTTTTTATTTTGACTGTTTTACCATAAGGTCACATATAGGAAACCCCCACTGTCCTAATAAAAA
>RD_seq6 CTAATCTCCTGTTGGCTGACTTACATCAGTTTGGGAAGTTGTTCATGATGACTCTGCGACGATCAAGAAG GACCAGGACTCTCCCTGGACACCTCAGGGACTTCTTGCTGGAGGGCACCATACATCAGTTTGCCAGCAAA
这是我用于LinearSVC的代码:
import pandas as pdimport numpy as npfrom numpy import arrayfrom numpy import argmaxfrom Bio import SeqIOfrom sklearn.preprocessing import LabelEncoderfrom sklearn.preprocessing import OneHotEncoderfrom sklearn.model_selection import train_test_splitwith open('../fasta/seqs_for_test.fasta') as fasta_file: # Will close handle cleanly identifiers = [] sequences = [] for seq_record in SeqIO.parse(fasta_file, 'fasta'): # (generator) identifiers.append(seq_record.id) sequences.append(seq_record.seq.lower())s1 = pd.Series(identifiers, name='ID')s2 = pd.Series(sequences, name='sequence')# Gathering Series into a pandas DataFrame and rename index as ID columnfasta_frame = pd.DataFrame(dict(ID=s1, sequence=s2)).set_index(['ID'])fasta_framelabel_serie = pd.Series()fasta_frame.insert(1, "label", label_serie)# Transposable element (TE) == 0; Random (RD) == 1.fasta_frame.loc[fasta_frame.index.str.contains(r'TE_'),'label'] = 0fasta_frame.loc[fasta_frame.index.str.contains(r'RD_'),'label'] = 1fasta_frame# empty list to store ohe array sequencesres_arr = []for index, row in fasta_frame['sequence'].iteritems(): # integer encode label_encoder = LabelEncoder() integer_encoded = label_encoder.fit_transform(row) # print(integer_encoded) # binary encode onehot_encoder = OneHotEncoder(sparse=False) integer_encoded = integer_encoded.reshape(len(integer_encoded), 1) onehot_encoded = onehot_encoder.fit_transform(integer_encoded)# print(index)# print(onehot_encoded) # append ohe arrays res_arr.append(onehot_encoded)y = fasta_frame['label']# yfrom sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(res_arr, y, test_size = 0.20, random_state=42)# print(x_train)# print(y_train)# print(x_test)# print(y_test)from sklearn.svm import LinearSVCfrom sklearn.metrics import accuracy_scoremodelo = LinearSVC()modelo.fit(x_train, y_train)previsoes = modelo.predict(y_test)acuracia = accuracy_score(y_test, previsoes) * 100print("accuracy was %.2f%%" % acuracia)
我尝试过重塑、np.vstack等方法,但都没有成功。我该如何使用数组列表作为我的训练集呢?
错误信息:
ValueError: Found array with dim 3. Estimator expected <= 2.
回答:
你的问题在于SVM期望每个训练样本具有固定数量的n个一维特征,然后尝试在这个n维特征空间中找到一个分隔超平面。如果你对长度为m的DNA序列进行独热编码,你实际上会得到m个4维特征。LinearSVC的实现并不适应这种情况(我不确定SVM是否普遍适用于非一维特征,任意维度的特征应该如何构成一个空间?)。
如果你想使用sklearn的SVM实现,你必须找到一种方法“形式上”将你的特征维度减少到一维。一种可能性是展平你的序列表示。即从一个维度为[140, 4]的DNA序列开始,你通过在同一维度上连接独热表示,创建一个维度为[560, 1]的展平表示。
或许一个例子可以说明问题:
给定一个示例DNA序列“AC”被独热编码为[[1, 0, 0, 0], [0, 1, 0, 0]]。然后你必须将输入展平为[1, 0, 0, 0, 0, 1, 0, 0],这样你就可以在长度为2的DNA序列上训练SVM。
为什么这行得通呢?
SVM将有8个权重(忽略偏置项)。第一个权重将权衡腺嘌呤作为第一个核苷酸出现的重要性。第二个权重将权衡胞嘧啶作为第一个核苷酸出现的重要性。第五个权重将权衡腺嘌呤作为第二个核苷酸出现的重要性,依此类推。现在,如果“AC”DNA序列出现并且我们想对其进行分类,除了腺嘌呤作为第一个核苷酸和胞嘧啶作为第二个核苷酸对应的权重外,所有权重都将被忽略。
如果你的DNA序列不是固定长度的,你将需要对它们进行零填充。这意味着在它们的展平序列表示后面添加零,直到它们与数据集中最长的序列一样长。