Построение SVM с помощью LinearClassifier tensflow и Dataframes Panda - PullRequest
2 голосов
/ 29 марта 2019

Мне известен этот вопрос , но он для устаревшей функции.

Допустим, я пытаюсь предсказать, посетит ли человек страну «Х», учитывая страны, которые он уже посетил, и его доход.

У меня есть набор данных тренировки в пандусном фрейме данных в следующем формате.

  1. Каждый ряд представляет отдельного человека, каждый из которых не связан с другими в матрице.
  2. Первые 10 столбцов - это названия стран, а значения в столбце являются двоичными (1, если они посетили эту страну, или 0, если они этого не сделали).
  3. Столбец 11 - их доход.Это непрерывная десятичная переменная.
  4. Наконец, столбец 12 - это еще одна двоичная таблица, в которой указано, посещали они «Х» или нет.

По сути, если в моем наборе данных 100 000 человек, то у меня есть размер данных 100,000 x 12.Я хочу быть в состоянии правильно передать это в линейный классификатор с использованием тензорного потока.Но не уверен даже, как подойти к этому.

Я пытаюсь передать данные в эту функцию

estimator = LinearClassifier(
    n_classes=n_classes, feature_columns=[sparse_column_a, 
 sparse_feature_a_x_sparse_feature_b], label_keys=label_keys)

(Если есть лучшее предложение по использованию оценщика, я буду открыт для попыткичто.)

И я передаю данные как:

df = pd.DataFrame(np.random.randint(0,2,size=(100, 12)), columns=list('ABCDEFGHIJKL'))
tf_val = tf.estimator.inputs.pandas_input_fn(X.iloc[:, 0:9], X.iloc[:, 11], shuffle=True)

Однако я не уверен, как принять этот вывод и правильно передать в классификатор.Я правильно настраиваю проблему?Я не из истории науки, поэтому любое руководство будет очень полезным!

Касается

  1. Столбец 11 - ковариата.Следовательно, я не думаю, что это можно просто передать как функцию, не так ли?
  2. Как я могу также включить столбец 11 в классификатор, поскольку столбец 11 - это объект совершенно другого типа, чем столбцы с 1 по 10.
  3. По крайней мере, даже если я игнорирую столбец11, как мне, по крайней мере, соответствовать столбцу с 1 по 10, с меткой = столбец 12 и передать его в классификатор?

(рабочий код, необходимый для вознаграждения)

Ответы [ 2 ]

4 голосов
/ 04 апреля 2019

Линейный SVM

SVM является классификатором максимальной маржи, т.е. он максимизирует ширину или границу, отделяющую положительный класс от отрицательного.Функция потерь линейного SVM в случае двоичной классификации приведена ниже.

enter image description here

Она может быть получена из более обобщенного мультикласса линейных потерь SVM (также называется потерей шарнира), показанным ниже (с Δ = 1).

enter image description here enter image description here

Примечание: во всех вышеперечисленныхУравнения, весовой вектор w включает в себя смещение b

Как, черт возьми, кто-то придумал эту потерю? Позволяет раскопать.

enter image description here

На изображении выше показаны точки данных, принадлежащие положительному классу, отделенные от точки данных, принадлежащей отрицательному классу, разделяющей гиперплоскостью (показана сплошной линией).Однако таких разделяющих гиперплоскостей может быть много.SVM находит разделяющую гиперплоскость так, чтобы расстояние гиперплоскости до ближайшей положительной точки данных и до ближайшей отрицательной точки данных было максимальным (показано пунктирной линией).

Математически SVM находит вектор весов w (включая смещение), такой что

enter image description here

Если метки (y) из + ve class и -ve class равны +1 и -1 соответственно, тогда SVM находит w такой, что

enter image description here

• Еслиточка данных находится на правильной стороне гиперплоскости (правильно классифицирована), тогда

enter image description here

• Если точка данных находится на неправильной стороне (пропущена классификация) затем

enter image description here

Таким образом, потеря для точки данных, которая является мерой классификации ошибок, может быть записана как

enter image description here

Регуляризация

Если вектор весов w правильно классифицирует данные (X), то любой кратный из этих векторов весов λw, где λ>1также правильно классифицирует данные (ноль потерь).Это потому, что преобразование λW растягивает все балльные значения и, следовательно, также их абсолютные различия.Регуляризация L2 штрафует большие веса, добавляя потерю регуляризации к потере шарнира.

enter image description here

Например, если x=[1,1,1,1] и два весовых вектора w1=[1,0,0,0], w2=[0.25,0.25,0.25,0.25].Тогда dot(W1,x) =dot(w2,x) =1, т.е. оба вектора веса приводят к одному и тому же точечному произведению и, следовательно, к одинаковой потере шарнира.Но штраф L2 w1 составляет 1.0, в то время как штраф L2 w2 составляет всего 0.25.Следовательно, регуляризация L2 предпочитает w2 над w1.Классификатор рекомендуется принимать во внимание все входные измерения в небольших количествах, а не несколько входных измерений и очень сильно.Это улучшает обобщение модели и приводит к меньшему переоснащению.

L2 штраф приводит к свойству максимального запаса в SVM.Если SVM выражается как задача оптимизации, то обобщенная форма Лагранжа для задачи ограниченной квадратичной оптимизации выглядит следующим образом:

enter image description here

Теперь, когда мы знаем потериВ функции линейного SVM мы можем использовать градиент приличный (или другие оптимизаторы), чтобы найти весовые векторы, которые минимизируют потери.

Код

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

# Load Data
iris = datasets.load_iris()
X = iris.data[:, :2][iris.target != 2]
y = iris.target[iris.target != 2]

# Change labels to +1 and -1 
y = np.where(y==1, y, -1)

# Linear Model with L2 regularization
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation='linear', kernel_regularizer=tf.keras.regularizers.l2()))

# Hinge loss
def hinge_loss(y_true, y_pred):    
    return tf.maximum(0., 1- y_true*y_pred)

# Train the model
model.compile(optimizer='adam', loss=hinge_loss)
model.fit(X, y,  epochs=50000, verbose=False)

# Plot the learned decision boundary 
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
                         np.arange(y_min, y_max, 0.01))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.show()

enter image description here

SVM также можно выразить как ограниченную задачу квадратичной оптимизации.Преимущество этой формулировки состоит в том, что мы можем использовать трюк ядра для классификации нелинейно разделимых данных (используя разные ядра).LIBSVM реализует алгоритм последовательной минимальной оптимизации (SMO) для машин с ядрами опорных векторов (SVM).

Код

from sklearn.svm import SVC
# SVM with linear kernel
clf = SVC(kernel='linear')
clf.fit(X, y) 

# Plot the learned decision boundary 
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
                         np.arange(y_min, y_max, 0.01))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.show() 

enter image description here

Наконец

Линейная модель SVM с использованием tf, которую вы можете использовать дляпостановка задачи:

# Prepare Data 
# 10 Binary features
df = pd.DataFrame(np.random.randint(0,2,size=(1000, 10)))
# 1 floating value feature 
df[11] = np.random.uniform(0,100000, size=(1000))
# True Label 
df[12] = pd.DataFrame(np.random.randint(0, 2, size=(1000)))

# Convert data to zero mean unit variance 
scalar = StandardScaler().fit(df[df.columns.drop(12)])
X = scalar.transform(df[df.columns.drop(12)])
y = np.array(df[12])

# convert label to +1 and -1. Needed for hinge loss
y = np.where(y==1, +1, -1)

# Model 
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation='linear', 
                                kernel_regularizer=tf.keras.regularizers.l2()))
# Hinge Loss
def my_loss(y_true, y_pred):    
    return tf.maximum(0., 1- y_true*y_pred)

# Train model 
model.compile(optimizer='adam', loss=my_loss)
model.fit(X, y,  epochs=100, verbose=True)

Кросс-фолд-кросс-валидация и прогнозирование

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import KFold
from sklearn.metrics import roc_curve, auc

# Load Data
iris = datasets.load_iris()
X = iris.data[:, :2][iris.target != 2]
y_ = iris.target[iris.target != 2]

# Change labels to +1 and -1 
y = np.where(y_==1, +1, -1)


# Hinge loss
def hinge_loss(y_true, y_pred):    
    return tf.maximum(0., 1- y_true*y_pred)

def get_model():
    # Linear Model with L2 regularization
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Dense(1, activation='linear', kernel_regularizer=tf.keras.regularizers.l2()))
    model.compile(optimizer='adam', loss=hinge_loss)
    return model

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

predict = lambda model, x : sigmoid(model.predict(x).reshape(-1))
predict_class = lambda model, x : np.where(predict(model, x)>0.5, 1, 0)


kf = KFold(n_splits=2, shuffle=True)

# K Fold cross validation
best = (None, -1)

for i, (train_index, test_index) in enumerate(kf.split(X)):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

    model = get_model()
    model.fit(X_train, y_train, epochs=5000, verbose=False, batch_size=128)
    y_pred = model.predict_classes(X_test)
    val = roc_auc_score(y_test, y_pred)    
    print ("CV Fold {0}: AUC: {1}".format(i+1, auc))
    if best[1] < val:
        best = (model, val)

# ROC Curve using the best model
y_score = predict(best[0], X)
fpr, tpr, _ = roc_curve(y_, y_score)
roc_auc = auc(fpr, tpr)
print (roc_auc)

# Plot ROC
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
         lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc="lower right")
plt.show()

# Make predictions
y_score = predict_class(best[0], X)

прогнозирование

Поскольку выходные данные модели являются линейными, мы должны нормализовать ее для вероятностей, чтобы делать прогнозы. Если это бинарная классификация, мы можем использовать sigmoid, если это мультиклассовая классификация, то мы можем использовать softmax. Ниже приведен код для двоичной классификации

predict = lambda model, x : sigmoid(model.predict(x).reshape(-1))
predict_class = lambda model, x : np.where(predict(model, x)>0.5, 1, 0)

Ссылки

  1. CS231n
  2. Мой блокнот Kaggle
1 голос
/ 02 апреля 2019

Поскольку все ваши функции уже числовые, вы можете использовать их как есть.

df = pd.DataFrame(np.random.randint(0,2,size=(100, 12)), columns=list('ABCDEFGHIJKL'))
df['K'] = np.random.random(100)
nuemric_features = [tf.feature_column.numeric_column(column) for column in df.columns[:11]]
model = tf.estimator.LinearClassifier(feature_columns=nuemric_features)
tf_val = tf.estimator.inputs.pandas_input_fn(df.iloc[:,:11], df.iloc[:,11], shuffle=True)
model.train(input_fn=tf_val, steps=1000)

print(list(model.predict(input_fn=tf_val))[0])
{'logits': array([-1.7512109], dtype=float32), 'logistic': array([0.14789453], dtype=float32), 'probabilities': array([0.8521055 , 0.14789453], dtype=float32), 'class_ids': array([0]), 'classes': array([b'0'], dtype=object)}

Вероятности выходных данных прогноза, скорее всего, вас интересуют. У вас есть две вероятности: одна для цели - Flase, а другая - для True.

Если вы хотите получить более подробную информацию, посмотрите этот хороший пост в блоге о бинарной классификации с TensorFlow.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...