使用 Sci-kit Learn SVM 时预测始终相同
Prediction always the same while using Sci-kit Learn SVM
我有一个数据集,我试图从 DNA 构成中预测数据条目是哪种 DNA。例如,字符串 ATTAG...ACGAT
可能会转换为 EI
。可能的输出是 EI
、IE
或 N
。可以进一步研究数据集 here。我尝试将内核从 linear
切换到 rbf
,但结果是一样的。 SVM 分类器似乎每次都输出 N
。任何想法为什么?我是 Sci-kit Learn 的初学者。
import pandas as pd
# 3190 total
training_data = pd.read_csv('new_training.csv')
test_data = pd.read_csv('new_test.csv')
frames = [training_data, test_data]
data = pd.concat(frames)
x = data.iloc[:, 0:59]
y = data.iloc[:, 60]
x = pd.get_dummies(x)
train_x = x.iloc[0:3000, :]
train_y = y.iloc[0:3000]
test_x = x.iloc[3000:3190, :]
test_y = y.iloc[3000:3190]
from sklearn import svm
from sklearn import preprocessing
clf = svm.SVC(kernel="rbf")
label_encoder = preprocessing.LabelEncoder()
label_encoder.fit(y)
print(label_encoder.transform(train_y))
clf.fit(train_x, label_encoder.transform(train_y))
for u in train_y.unique():
print(u)
predictions = clf.predict(test_x)
correct = 0
total = len(predictions)
for i in range(total):
prediction = label_encoder.inverse_transform(predictions[i])
print('predicted %s and actual %s' % (prediction, test_y[i]))
print(len(prediction))
if prediction == test_y[i]:
correct += 1
print('correct %d out of %d' % (correct, total))
首先,我导入训练和测试数据,将其组合并将其拆分为 x(输入)或 y(输出标签)。然后我将 x 转换为虚拟变量版本,从原来的 60 列变成 300~ 列,因为每个 DNA 点可以是 A
、T
、G
、C
,有时N
。对于每个输入的所有可能输入,基本上都有 0 或 1。 (有没有更好的方法来做到这一点?Sci-kit 学习不支持分类编码,我尽我所能从 this。)然后我再次分离数据(我必须合并以便我可以生成整个数据的假人 space).
从这里开始,我只是 运行 svm 东西以适应 x
和 y
标签,然后在 test_x
上进行预测。我也只好encode/labely
,从字符串版到数字版。但是,是的,它总是产生 N
,我觉得这是错误的。我该如何解决?谢谢!
我认为问题在于将数据拆分为训练和测试的方式。您已将前 3000 个样本用于训练,将剩余的 190 个样本用于测试。我发现通过这样的训练,classifier 为所有测试样本生成了真实的 class 标签(score = 1.0)。我还注意到数据集的最后 190 个样本具有 相同的 class 标签 ,即 'N'
。所以你得到的结果是正确的。
我建议您将数据集拆分为训练并通过 ShuffleSplit
with test_size=.06
(this corresponds approximately to 190/3190 although to make visualization of results easier I used test_size=.01
in the sample run below). For the sake of simplicity I would also suggest you to use OneHotEncoder
进行测试以对特征的分类值进行编码。
这是完整的代码(我冒昧地进行了一些重构):
import numpy as np
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn.model_selection import ShuffleSplit
from sklearn import svm
data = np.loadtxt(r'splice.data', delimiter=',', dtype='string')
bases = {'A': 0, 'C': 1, 'D': 2, 'G': 3, 'N': 4, 'R': 5, 'S': 6, 'T': 7}
X_base = np.asarray([[bases[c] for c in seq.strip()] for seq in data[:, 2]])
y_class = data[:, 0]
enc = OneHotEncoder(n_values=len(bases))
lb = LabelEncoder()
enc.fit(X_base)
lb.fit(y_class)
X = enc.transform(X_base).toarray()
y = lb.transform(y_class)
rs = ShuffleSplit(n_splits=1, test_size=.01, random_state=0)
train_index, test_index = rs.split(X).next()
train_X, train_y = X[train_index], y[train_index]
test_X, test_y = X[test_index], y[test_index]
clf = svm.SVC(kernel="rbf")
clf.fit(train_X, train_y)
predictions = clf.predict(test_X)
演示:
Out[2]:
array(['IE', 'EI', 'EI', 'EI', 'EI', 'IE', 'N', 'N', 'EI', 'N', 'N', 'IE',
'IE', 'N', 'N', 'IE', 'EI', 'N', 'N', 'EI', 'IE', 'EI', 'IE', 'N',
'EI', 'N', 'IE', 'N', 'EI', 'N', 'N', 'EI'],
dtype='|S79')
In [3]: y_class[test_index]
Out[3]:
array(['IE', 'EI', 'EI', 'EI', 'EI', 'IE', 'N', 'N', 'EI', 'N', 'N', 'IE',
'IE', 'N', 'N', 'IE', 'EI', 'N', 'N', 'EI', 'IE', 'EI', 'IE', 'N',
'IE', 'N', 'IE', 'N', 'EI', 'N', 'N', 'EI'],
dtype='|S79')
In [4]: clf.score(test_X, test_y)
Out[4]: 0.96875
注意:确保你的sklearn版本是0.18.1,否则上面的代码可能无法运行。
我有一个数据集,我试图从 DNA 构成中预测数据条目是哪种 DNA。例如,字符串 ATTAG...ACGAT
可能会转换为 EI
。可能的输出是 EI
、IE
或 N
。可以进一步研究数据集 here。我尝试将内核从 linear
切换到 rbf
,但结果是一样的。 SVM 分类器似乎每次都输出 N
。任何想法为什么?我是 Sci-kit Learn 的初学者。
import pandas as pd
# 3190 total
training_data = pd.read_csv('new_training.csv')
test_data = pd.read_csv('new_test.csv')
frames = [training_data, test_data]
data = pd.concat(frames)
x = data.iloc[:, 0:59]
y = data.iloc[:, 60]
x = pd.get_dummies(x)
train_x = x.iloc[0:3000, :]
train_y = y.iloc[0:3000]
test_x = x.iloc[3000:3190, :]
test_y = y.iloc[3000:3190]
from sklearn import svm
from sklearn import preprocessing
clf = svm.SVC(kernel="rbf")
label_encoder = preprocessing.LabelEncoder()
label_encoder.fit(y)
print(label_encoder.transform(train_y))
clf.fit(train_x, label_encoder.transform(train_y))
for u in train_y.unique():
print(u)
predictions = clf.predict(test_x)
correct = 0
total = len(predictions)
for i in range(total):
prediction = label_encoder.inverse_transform(predictions[i])
print('predicted %s and actual %s' % (prediction, test_y[i]))
print(len(prediction))
if prediction == test_y[i]:
correct += 1
print('correct %d out of %d' % (correct, total))
首先,我导入训练和测试数据,将其组合并将其拆分为 x(输入)或 y(输出标签)。然后我将 x 转换为虚拟变量版本,从原来的 60 列变成 300~ 列,因为每个 DNA 点可以是 A
、T
、G
、C
,有时N
。对于每个输入的所有可能输入,基本上都有 0 或 1。 (有没有更好的方法来做到这一点?Sci-kit 学习不支持分类编码,我尽我所能从 this。)然后我再次分离数据(我必须合并以便我可以生成整个数据的假人 space).
从这里开始,我只是 运行 svm 东西以适应 x
和 y
标签,然后在 test_x
上进行预测。我也只好encode/labely
,从字符串版到数字版。但是,是的,它总是产生 N
,我觉得这是错误的。我该如何解决?谢谢!
我认为问题在于将数据拆分为训练和测试的方式。您已将前 3000 个样本用于训练,将剩余的 190 个样本用于测试。我发现通过这样的训练,classifier 为所有测试样本生成了真实的 class 标签(score = 1.0)。我还注意到数据集的最后 190 个样本具有 相同的 class 标签 ,即 'N'
。所以你得到的结果是正确的。
我建议您将数据集拆分为训练并通过 ShuffleSplit
with test_size=.06
(this corresponds approximately to 190/3190 although to make visualization of results easier I used test_size=.01
in the sample run below). For the sake of simplicity I would also suggest you to use OneHotEncoder
进行测试以对特征的分类值进行编码。
这是完整的代码(我冒昧地进行了一些重构):
import numpy as np
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn.model_selection import ShuffleSplit
from sklearn import svm
data = np.loadtxt(r'splice.data', delimiter=',', dtype='string')
bases = {'A': 0, 'C': 1, 'D': 2, 'G': 3, 'N': 4, 'R': 5, 'S': 6, 'T': 7}
X_base = np.asarray([[bases[c] for c in seq.strip()] for seq in data[:, 2]])
y_class = data[:, 0]
enc = OneHotEncoder(n_values=len(bases))
lb = LabelEncoder()
enc.fit(X_base)
lb.fit(y_class)
X = enc.transform(X_base).toarray()
y = lb.transform(y_class)
rs = ShuffleSplit(n_splits=1, test_size=.01, random_state=0)
train_index, test_index = rs.split(X).next()
train_X, train_y = X[train_index], y[train_index]
test_X, test_y = X[test_index], y[test_index]
clf = svm.SVC(kernel="rbf")
clf.fit(train_X, train_y)
predictions = clf.predict(test_X)
演示:
Out[2]:
array(['IE', 'EI', 'EI', 'EI', 'EI', 'IE', 'N', 'N', 'EI', 'N', 'N', 'IE',
'IE', 'N', 'N', 'IE', 'EI', 'N', 'N', 'EI', 'IE', 'EI', 'IE', 'N',
'EI', 'N', 'IE', 'N', 'EI', 'N', 'N', 'EI'],
dtype='|S79')
In [3]: y_class[test_index]
Out[3]:
array(['IE', 'EI', 'EI', 'EI', 'EI', 'IE', 'N', 'N', 'EI', 'N', 'N', 'IE',
'IE', 'N', 'N', 'IE', 'EI', 'N', 'N', 'EI', 'IE', 'EI', 'IE', 'N',
'IE', 'N', 'IE', 'N', 'EI', 'N', 'N', 'EI'],
dtype='|S79')
In [4]: clf.score(test_X, test_y)
Out[4]: 0.96875
注意:确保你的sklearn版本是0.18.1,否则上面的代码可能无法运行。