使用Tensorflow的LinearClassifier和Panda的数据框构建SVM

时间:2019-03-29 20:15:17

标签: python pandas tensorflow machine-learning svm

我知道这个question,但这是过时的功能。

比方说,我正在尝试根据某人已经访问过的国家和他们的收入来预测一个人是否会访问“ X”国。

我在pandas DataFrame中有一个训练数据集,格式如下。

  1. 每一行代表一个不同的人,每个人与矩阵中的其他人无关。
  2. 前10列均为国家/地区名称, 该列为二进制(如果他们访问过该国家,则为1;如果访问过该国家,则为0 他们没有)。
  3. 第11栏是他们的收入。这是一个连续的十进制变量。
  4. 最后,第12列是另一个二进制表,表示是,他们是否访问过“ X”。

从本质上讲,如果我的数据集中有100,000个人,那么我的数据框的尺寸为100,000 x 12。我希望能够使用tensorflow将其正确传递到线性分类器中。但是,即使是如何处理,也不确定。

我正在尝试将数据传递到此function

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列是与第1列到第10列完全不同的功能,因此我也如何将第11列并入分类器中。
  3. 至少,即使我忽略第11列,如何至少将第1列到第10列与label =第12列配合,并将其传递给分类器?

(赏金所需的工作代码)

2 个答案:

答案 0 :(得分:3)

线性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

如果+ ve类和-ve类的标签(y)分别是+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,即两个权重向量都导致相同的点积,从而导致相同的铰链损耗。但是w1的L2惩罚为1.0,而w2的L2惩罚仅为0.25。因此,L2正则化比w2更喜欢w1。鼓励分类器将所有输入维考虑为少量,而不是少数几个输入维。这样可以改善模型的通用性,并减少过拟合。

L2损失导致SVM中的最大保证金属性。如果将SVM表示为优化问题,则约束二次优化问题的广义Lagrangian形式如下

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为内核化支持向量机(SVM)实现了顺序最小优化(SMO)算法。

代码

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

最后

您可以将tf用于问题陈述的线性SVM模型是

# 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)

K折交叉验证并做出预测

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. My Kaggle notebook

答案 1 :(得分:1)

由于所有功能都已经是数字功能,因此您可以按原样使用它们。

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进行二进制分类的不错的blog-post