不使用 train_test_split 方法对 sklearn 的 SVM 进行数据预处理

Posted

技术标签:

【中文标题】不使用 train_test_split 方法对 sklearn 的 SVM 进行数据预处理【英文标题】:Data pre-processing for sklearn's SVM without using the train_test_split method 【发布时间】:2019-06-28 19:39:16 【问题描述】:

我使用 Inception 并为大约 11000 个视频生成了 1000 个特征(对象的概率)。这些视频已经按类型分类,我希望 SVM 预测视频属于哪个类型。

我想将 SVM 应用于这些特征向量,但到目前为止我阅读的每个教程都使用了来自 sklearn.model_selectiontrain_test_split 方法。

我的数据看起来如何:

我已将我的数据集分成两个 csv 文件,其中包含约 9000 条训练和约 2000 条测试(每个都有 1000 个特征)记录。格式为videoId,feature1,feature2,...,feature1000

我有以流派为标题的文件,例如Training/education.txt 用于训练,Testing/education.txt 用于测试。每个文件都包含属于所述类型的videoIds。

我是数据科学和 pandas、sklearn 等库的新手,所以我不知道应该如何准备这些数据。我一直在关注this guide:

import pandas as pd  

bankdata = pd.read_csv("D:/Datasets/bill_authentication.csv")  
X = bankdata.drop('Class', axis=1)  
y = bankdata['Class']  
from sklearn.model_selection import train_test_split  
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)  

我将如何获得X_trainX_testy_trainy_test?由于我目前的数据设置方式,我无法使用像 train_test_split 这样的方法。

【问题讨论】:

【参考方案1】:

所有教程都建议您使用 train_test_splitsklearn.model.selection 的原因是因为他们假设您想要评估学习模型的性能,并可能在最终使用它来生成预测之前调整它的超参数你的测试数据集。

这种做法称为搁置“交叉验证”集。为此,您暂时保持测试集不变,实际上拆分了大约 20% 的训练集行。您在训练集的 80% 行上训练模型,并使用该模型对剩余 20% 的训练集生成预测。

您可以选择一个指标,例如accuracy,来判断您的模型的性能。通常,此时您会想要尝试为模型的hyperparameters 尝试不同的值,并查看其在验证集(训练集的最后 20%)上的得分是否有所提高。

train_test_split 方法只是将您的训练数据分成这些 80/20 部分的简单方法。我建议你不要跳过这一步。原因是,如果您在观察模型在您的实际测试集上的表现之后更改模型或其超参数,您将失去了解模型在全新、真实的- 世界数据。

这被称为“对测试集的过度拟合”,这是一种常见的实践错误,导致机器学习模型在一组先前收集的数据上表现非常出色,但最终(令其创造者感到惊讶)这些模型在最终投入生产时看到的真实数据表现非常糟糕。

总而言之,这个想法是你:

    使用 80% 的训练数据进行训练。 评估 20% 的火车数据。 更改您的模型,直到您对它在步骤 (2.) 中使用的数据的评分方式感到满意为止。 最后,仅在最后,使用您的模型对您的实际测试数据进行预测。

顺便说一句,Sklearn 对方法train_test_split 的命名有些混乱,因为该方法的目的是创建验证集。 (train_val_split 在我看来是一个更直观的名字……)

以下是代码中的步骤,我想您会根据您的特定情况(数据拆分为多个 .txt 文件)进行操作:

    导入模块和所有训练 .csv 文件:
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

X_edu = pd.read_csv('Training/education.txt')
X_hor = pd.read_csv('Training/horror.txt')
...
    在每个类型的数据帧中创建一个Genre 列,然后将所有这些连接到一个数据帧中:
train_dfs = [X_edu, X_hor, ...]
genres = ['edu', 'hor', ...]
for i, genre in enumerate(genres):
    train_dfs[i]['Genre'] = genre

X = pd.concat[train_dfs].reset_index(drop=True) # reset the index so each row has a unique index
                                                # important so we can be sure we can properly match each row with its label
    从训练数据中提取标签(我假设标签位于标题为Genre 或类似名称的列中)并删除videoID 列(因为它似乎不是预测功能):
y = X['Genre']
X = X.drop(['Genre', 'videoID'], axis=1)
    使用 train_test_split 创建您的训练和验证集(不错的奖励:train_test_split 在拆分之前自动打乱整个训练数据帧的行,因此您不必担心某些类型不在您的验证中设置):
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = 0.20)
    将您的模型拟合到 X_train 并在 X_val 上进行预测:
clf = SVC()
clf.fit(X_train, y_train)
preds = clf.predict(X_val)
    确定您的模型在验证集上做出的这些预测的性能(我在这里使用准确度,但您可以使用任何您想要的指标——Sklearn 可能为您想要使用的任何指标提供一个类。)
val_acc = accuracy_score(y_val, preds)

    为您的 SVM 学习者的 hyperparameters 尝试不同的值,然后重复上述步骤 (5.) 和 (6.)。当您对模型的性能感到满意时,就可以根据实际测试数据生成预测了。

    您可以为每种类型加载测试 .csv 文件,并将它们全部组合到一个数据帧中,就像您对上面的训练数据所做的那样:

test_edu = pd.read_csv('Training/education.txt')
test_hor = pd.read_csv('Training/horror.txt')
...

test_dfs = [test_edu, test_hor, ...]
for i, genre in enumerate(genres):
    test_dfs[i]['Genre'] = genre

test = pd.concat[test_dfs].reset_index(drop=True) # reset the index so each row has a unique index
y_test = test['Genre']
X_test = test.drop(['Genre', 'videoID'], axis=1)
test_preds = clf.predict(X_test)
test_acc = accuracy_score(y_test, test_preds)

如果要求模型对从未见过的全新视频进行预测,该测试集准确度分数应该可以为您提供最真实的估计。

【讨论】:

以上是关于不使用 train_test_split 方法对 sklearn 的 SVM 进行数据预处理的主要内容,如果未能解决你的问题,请参考以下文章

scikit learn的train_test_split()方法

sklearn.model_selection.train_test_split 中分层方法的(无效参数)错误

sklearn.model_selection.train_test_split 用法

使用 train_test_split 后分类器准确率为 100%

sklearn 的 train_test_split 中的 random_state 参数

KFolds 交叉验证与 train_test_split