Прогноз всегда одинаков при использовании Sci-kit Learn SVM

У меня есть набор данных, в котором я пытаюсь предсказать, какая ДНК представляет собой запись данных по составу ДНК. Например, строка ATTAG...ACGAT может быть преобразована в EI. Возможные выходные значения: EI, IE или N. Набор данных можно дополнительно изучить здесь< /а>. Пробовал переключать ядра с 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~ столбцов, поскольку каждое пятно ДНК может быть A, T, G, C, а иногда и N. В основном есть либо 0, либо 1 для всех возможных входов для каждого входа. (Есть ли лучший способ сделать это? Sci-kit Learn не поддерживает категориальное кодирование, и я старался изо всех сил из this.) Затем я снова разделяю данные (мне пришлось объединиться, чтобы я мог генерировать макеты для всего пространства данных).

Отсюда я просто запускаю материал svm, чтобы соответствовать меткам x и y, а затем предсказывать test_x. Мне также пришлось закодировать/пометить y из строковой версии в числовую версию. Но да, он всегда выдавал N, что мне кажется неправильным. Как исправить? Благодарю вас!


person Sticky    schedule 03.02.2017    source источник
comment
Попробуйте другие классификаторы, такие как LinearSVC() или KNeighborsClassifer(), и проверьте, все ли они дают одинаковые ответы. Если да, то вам может потребоваться проверить свои данные.   -  person Vivek Kumar    schedule 03.02.2017
comment
Вы использовали набор данных как есть или изменили его перед импортом?   -  person Maximilian Peters    schedule 03.02.2017
comment
Я изменил набор данных, чтобы каждое пятно ДНК было отдельной переменной, поэтому у меня должно быть 60 переменных признаков и 1 выходная метка.   -  person Sticky    schedule 03.02.2017
comment
Я также использовал библиотеку Orange для рандомизации набора данных и сохранения в разные файлы, поэтому мне пришлось снова объединить их в начале приведенного выше скрипта.   -  person Sticky    schedule 03.02.2017


Ответы (1)


Я думаю, проблема в том, как данные разбиваются на обучение и тестирование. Вы взяли первые 3000 образцов для обучения и оставшиеся 190 образцов для тестирования. Выяснил, что при таком обучении классификатор выдает истинную метку класса для всех тестовых выборок (score = 1,0). Я также заметил, что последние 190 образцов набора данных имеют одинаковую метку класса, а именно 'N'. Следовательно, полученный вами результат является правильным.

Я бы порекомендовал вам разделить набор данных на обучающие и протестировать через ShuffleSplit с test_size=.06 (это примерно соответствует 190/3190, хотя для облегчения визуализации результатов я использовал test_size=.01 в приведенном ниже примере). Для простоты я также предлагаю вам использовать OneHotEncoder< /a> для кодирования категориальных значений функций.

Вот полный код (я позволил себе провести некоторый рефакторинг):

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, иначе приведенный выше код может не работать.

person Tonechas    schedule 03.02.2017
comment
Ницца! Обратите внимание, что код будет работать только с Python 2, с Python 3 это будут data = numpy.loadtxt(r'splice.data', delimiter=',', dtype=bytes).astype(str) и train_index, test_index = rs.split(X).__next__(). - person Maximilian Peters; 03.02.2017
comment
Потрясающий! Спасибо :) Я попробую это - person Sticky; 03.02.2017
comment
Могу подтвердить работает! Я собираюсь больше смотреть на документы, чтобы лучше понять. Спасибо еще раз! - person Sticky; 03.02.2017
comment
Спасибо, что заметили это. Хороший улов! Я имел в виду n_values=[8]*60, но при условии, что все 60 функций могут принимать 8 категориальных значений, вы должны просто написать enc = OneHotEncoder(n_values=len(bases)). Я собираюсь отредактировать свой ответ, чтобы исправить эту ошибку. - person Tonechas; 04.02.2017