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

标签 python pandas tensorflow machine-learning svm

我知道这个question,但是它是针对过时的功能。
假设我正在尝试根据某人已经访问过的国家和他们的收入来预测一个人是否会访问“X”国。
我在pandas DataFrame中有一个训练数据集,格式如下。

  • 每行代表一个不同的人,每个人与矩阵中的其他人无关。
  • 前10列均为国家/地区名称,其中的值为
    该列为二进制(如果他们访问过该国家,则为1;如果是
    他们没有)。
  • 第11列是他们的收入。这是一个连续的十进制变量。
  • 最后,第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)
    
    但是,我不确定如何获取此输出并将其正确传递到分类器中。我可以正确设置问题了吗?我不是来自数据科学领域,因此任何指导都将非常有帮助!
    关注
  • 第11列是协变量。因此,我认为它不能仅作为功能部件传递,对吗?
  • 我也如何将第11列合并到分类器中,因为第11列是与第1列到第10列完全不同的功能类型。
  • 至少,即使我忽略第11列,如何至少将第1列到第10列与label =第12列匹配,并将其传递到分类器中?

  • (赏金所需的工作代码)

    最佳答案

    线性支持向量机

    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拉伸(stretch)了所有得分幅度,因此也拉伸(stretch)了它们的绝对差。 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中的最大 margin 属性。如果将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)
    

    引用
  • CS231n

  • 更新1:

    为了使代码与tf 2.0兼容,y的数据类型应与X相同。为此,请在y = np.where(.....行之后添加y = y.astype(np.float64)行。

    关于python - 使用Tensorflow的LinearClassifier和Panda的数据框构建SVM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55424906/

    相关文章:

    python - 如何在 Python 中使用日期时间和 scipy 峰值进行绘图?

    python - 比较 Pandas Dataframe 中行内的列值

    python - Pandas 中的过滤和替换子字符串

    tensorflow - 必须指定 Xcode 版本才能使用 Apple CROSSTOOL

    python - tensorflow 中 RNN 的编码器解码器模型

    python - 在时间序列分析中对 tf.data.dataset 进行批处理

    python - 转义包含在某些 html 标签中的引号

    python - 获取二叉搜索树的高度

    python - 无法在centos上安装psycopg2

    python - 在 pandas DF 中选择列