【问题标题】:SVM provided a bad result in my data. How to fix?SVM 在我的数据中提供了一个糟糕的结果。怎么修?
【发布时间】:2018-08-12 03:37:22
【问题描述】:

我有一个数据集,其中包含用于训练的510 样本和用于测试的127 样本,每个样本都有7680 特征。我想设计一个模型来预测来自训练数据的高度(cm)标签。目前,我使用了 SVM,但它提供了非常糟糕的结果。你能看看我的代码并给我一些cmets。您可以使用dataset 和可运行代码在您的机器上试用它

import numpy as np
from sklearn.svm import SVR

# Training Data
train_X = np.loadtxt('trainX.txt') # 510 x 7680
train_Y = np.loadtxt('trainY.txt') # 510 x 1
test_X = np.loadtxt('testX.txt')   # 127 x 7680
test_Y = np.loadtxt('testY.txt')   # 127 x 1

my_svr = SVR(C=1000, epsilon=0.2)
my_svr.fit(train_X,train_Y)

p_regression = my_svr.predict(test_X)
print (p_regression)
print (test_Y)

一些结果:

p_regression

[15.67367165 16.35094166 13.10510262 14.03943211 12.7116549  11.45071423
 13.27225207  9.44959181 10.45775627 13.23953143 14.95568324 11.35994414
 10.69531821 12.42556347 14.54712287 12.25965911  9.04101931 14.03604126
 12.41237627 13.51951317 10.36302674  9.86389635 11.41448842 15.67146184
 14.74764672 11.22794536 12.04429175 12.48199183 14.29790809 16.21724184
 10.94478135  9.68210872 14.8663311   8.62974573 15.17281425 12.97230127
  9.46515876 16.24388177 10.35742683 15.65336366 11.04652502 16.35094166
 14.03943211 10.29066405 13.27225207  9.44959181 10.45775627 13.23953143
 14.95568324 11.35994414 10.69531821 12.42556347 14.54712287 12.25965911
  9.04101931 14.03604126 12.41237627 13.51951317 10.36302674  9.86389635
 11.41448842 15.67146184 14.74764672 11.22794536 12.04429175 12.48199183
 14.29790809 16.21724184 10.94478135  9.68210872 14.8663311   8.62974573
 15.17281425 12.97230127  9.46515876 16.24388177 10.35742683 15.65336366
 11.04652502 16.35094166 14.03943211 10.29066405 13.27225207  9.44959181
 10.45775627 13.23953143 14.95568324 11.35994414 10.69531821 12.42556347
 14.54712287 12.25965911  9.04101931 14.03604126 12.41237627 13.51951317
 10.36302674  9.86389635 11.41448842 15.67146184 14.74764672 11.22794536
 12.04429175 12.48199183 14.29790809 16.21724184 10.94478135  9.68210872
 14.8663311   8.62974573 15.17281425 12.97230127  9.46515876 16.24388177
 10.35742683 15.65336366 11.04652502 16.35094166 14.03943211 10.29066405
 13.27225207  9.44959181 10.45775627 13.23953143 14.95568324 11.35994414
 10.69531821]

test_Y

[13. 14. 13. 15. 15. 17. 13. 17. 16. 12. 17.  6.  4.  3.  4.  6.  6.  8.
  9. 18.  3.  6.  4.  6.  7.  8. 11. 11. 13. 12. 12. 14. 13. 12. 15. 15.
 16. 15. 17. 18. 17. 14. 15. 17. 13. 17. 16. 12. 17.  6.  4.  3.  4.  6.
  6.  8.  9. 18.  3.  6.  4.  6.  7.  8. 11. 11. 13. 12. 12. 14. 13. 12.
 15. 15. 16. 15. 17. 18. 17. 14. 15. 17. 13. 17. 16. 12. 17.  6.  4.  3.
  4.  6.  6.  8.  9. 18.  3.  6.  4.  6.  7.  8. 11. 11. 13. 12. 12. 14.
 13. 12. 15. 15. 16. 15. 17. 18. 17. 14. 15. 17. 13. 17. 16. 12. 17.  6.
  4.]

【问题讨论】:

  • 最可能的原因是您只训练了一个 SVM 模型而没有进行任何类型的超参数优化。只是碰巧那些特定的超参数值对这些数据不利。当然,使用这些预测变量无法预测结果的情况总是存在的。
  • @George:谢谢。但是我尝试了一些超参数设置,但并没有提供好的结果。您认为我们可以使用其他方法代替 SVM 来完成我的任务吗?你更喜欢哪种方法?
  • 一个好的初始起点是使用随机森林(使用默认参数,但我一般会使用约 500-1000 棵树)。它们比 SVM 更容易调整,并且通常表现得足够好。我确实这样做了,但似乎无法获得好的结果;我的 MSE 为 21.7。有趣的是,在训练集上,我得到了 5.2 的袋外 MSE。这表明测试集存在“错误”。可能,测试数据分布与训练数据有很大不同。为了测试这一点,我创建了新的训练/测试数据并运行模型。这次我的 MSE 约为 5.1。
  • 很高兴听到这个消息。你能分享你的代码吗?
  • 我合并了训练集和测试集,并使用 510/127 样本拆分再次拆分它们。这样做并使用默认参数运行随机森林,我得到了 5.1。我尝试了不同的随机分割并得到了〜5.7,所以也许我只是在那里很幸运。 @Jame 的一个问题:您是否对训练数据进行了任何类型的预处理?你有没有机会进行特征选择?

标签: python machine-learning scikit-learn svm linear-regression


【解决方案1】:

这是一个类似的方法。我们将数据集拆分为traintesttrain 数据集将用于调整超参数和拟合不同的模型。然后我们将选择最佳(就 MSE 而言)模型并从 test 数据集中预测值。

所有经过训练(拟合)的模型都将保存为 Pickle 文件,以便稍后使用 joblib.load() 方法加载它们。

输出:

----------------------------- [SVR_rbf] ------------------------------
Fitting 3 folds for each of 4 candidates, totalling 12 fits
---------------------------- [SVR_linear] ----------------------------
Fitting 3 folds for each of 4 candidates, totalling 12 fits
------------------------------ [Ridge] -------------------------------
Fitting 3 folds for each of 7 candidates, totalling 21 fits
------------------------------ [Lasso] -------------------------------
Fitting 3 folds for each of 6 candidates, totalling 18 fits
--------------------------- [RandomForest] ---------------------------
Fitting 3 folds for each of 3 candidates, totalling 9 fits
----------------------------- [SVR_rbf] ------------------------------
Score:      44.88%
Parameters: {'SVR_rbf__C': 10, 'SVR_rbf__max_iter': 500}
**********************************************************************
---------------------------- [SVR_linear] ----------------------------
Score:      33.40%
Parameters: {'SVR_linear__C': 0.01, 'SVR_linear__max_iter': 1000}
**********************************************************************
------------------------------ [Ridge] -------------------------------
Score:      34.83%
Parameters: {'Ridge__alpha': 500, 'Ridge__max_iter': 200}
**********************************************************************
------------------------------ [Lasso] -------------------------------
Score:      22.90%
Parameters: {'Lasso__alpha': 0.1, 'Lasso__max_iter': 1000}
**********************************************************************
--------------------------- [RandomForest] ---------------------------
Score:      36.87%
Parameters: {'RandomForest__max_depth': 5, 'RandomForest__n_estimators': 250}
**********************************************************************
Mean Squared Error: {'SVR_rbf': 5.375, 'SVR_linear': 7.036, 'Ridge': 7.02, 'Lasso': 8.108, 'RandomForest': 9.475}

代码:

import os
#import contextlib
from operator import itemgetter
from pathlib import Path
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import SGDRegressor, Ridge, Lasso
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.externals import joblib


def get_data(path='.'):
    p = Path(path)
    kwargs = dict(delim_whitespace=True, header=None)
    X_train = pd.read_csv(list(p.glob('trainX.txt*'))[0], **kwargs)
    y_train = pd.read_csv(list(p.glob('trainY.txt*'))[0], **kwargs)
    X_test = pd.read_csv(list(p.glob('testX.txt*'))[0], **kwargs)
    y_test = pd.read_csv(list(p.glob('testY.txt*'))[0], **kwargs)
    return (pd.concat([X_train, X_test], ignore_index=True),
            pd.concat([y_train, y_test], ignore_index=True)[0])


def get_data_split(path='.', test_size=0.25):
    X, y = get_data(path)
    return train_test_split(X, y, test_size=test_size)


def tune_models_hyperparams(X, y, models, **common_grid_kwargs):
    grids = {}
    for model in models:
        print('{:-^70}'.format(' [' + model['name'] + '] '))
        pipe = Pipeline([
                    ("scale", StandardScaler()),
                    (model['name'], model['model'])   ])
        grids[model['name']] = (GridSearchCV(pipe,
                                           param_grid=model['param_grid'],
                                           **common_grid_kwargs)
                                  .fit(X, y))
        # saving single trained model ...
        joblib.dump(grids[model['name']], './{}.pkl'.format(model['name']))
    return grids


def get_best_model(grid, X_test, y_test,
                        metric_func=mean_squared_error):
    res = {name : round(metric_func(y_test, model.predict(X_test)), 3)
           for name, model in grid.items()}
    print('Mean Squared Error:', res)
    best_model_name = min(res, key=itemgetter(1))
    return grid[best_model_name]


def test_dataset(grid, X_test, y_test):
    res = {}
    for name, model in grid.items():
        y_pred = model.predict(X_test)
        res[name] = {'MSE': mean_squared_error(y_test, y_pred),
                       'R2': r2_score(y_test, y_pred)
                      }
    return res

def predict(grid, X_test, model_name):
    return grid[model_name].predict(X_test)


def print_grid_results(grids):
    for name, model in grids.items():
        print('{:-^70}'.format(' [' + name + '] '))
        print('Score:\t\t{:.2%}'.format(model.best_score_))
        print('Parameters:\t{}'.format(model.best_params_))
        print('*' * 70)


models = [
    {   'name':     'SVR_rbf',
        'model':    SVR(),
        'title':    "SVR_rbf",
        'param_grid': {
            'SVR_rbf__C':           [0.1, 1, 5, 10],
            'SVR_rbf__max_iter':    [500]
        } 
    },
    {   'name':     'SVR_linear',
        'model':      SVR(kernel='linear'),
        'title':    "SVR_rbf",
        'param_grid': {
            'SVR_linear__C':           [0.01, 0.1, 1, 5],
            'SVR_linear__max_iter':    [1000]
        } 
    },
    {   'name':     'Ridge',
        'model':    Ridge(),
        'title':    "Ridge",
        'param_grid': {
            'Ridge__alpha':         [0.1, 0.5, 5, 10, 50, 100, 500],
            'Ridge__max_iter':      [200]
        } 
    },
    {   'name':     'Lasso',
        'model':    Lasso(),
        'title':    "Lasso",
        'param_grid':  {
            'Lasso__alpha':         [0.0001, 0.001, 0.01, 0.1, 1, 10],
            'Lasso__max_iter':      [1000]
        } 
    },
    {   'name':     'RandomForest',
        'model':    RandomForestRegressor(),
        'title':    "RandomForest",
        'param_grid':  {
            'RandomForest__n_estimators':   [50, 250, 500],
            'RandomForest__max_depth':      [5],
        } 
    },
]


def main(path):
    os.chdir(str(path))

    X_train, X_test, y_train, y_test = \
        get_data_split(path, test_size=127/510.)
    grid = tune_models_hyperparams(X_train, y_train, models, cv=3,
                                   verbose=2, n_jobs=-1)
    print_grid_results(grid)
    model = get_best_model(grid, X_test, y_test)
    df = pd.DataFrame({'predicted': model.predict(X_test)})
    df.to_csv('predicted.csv', index=False)

if __name__ == "__main__":
    p =  Path(__file__).parent.resolve()
    main(p)

【讨论】:

  • 干得好。我去办公室的时候会检查一下。拆分数据集是否可以作为 k 折验证?
  • @Jame,不,这是一个简单的拆分 - 想法是对数据进行洗牌并随机选择大约 100 的训练和测试数据集。大小相同...您可能想在这里尝试不同的方法...
  • 谢谢。对于结果,你能告诉我为什么你的第一个答案和第二个答案给出不同的表现吗?第一个答案看起来更好
【解决方案2】:

我同意@George - "there is something "wrong" with the test set"。我得到了类似的 MSE 结果 - 大约。 21.

我还尝试将训练和测试数据集放在一起并将其提供给 GridSearchCV。

以下是这些尝试的结果:

In [33]: print_grid_results(grid)
----------------------------- [SVR_rbf] ------------------------------
Score:          48.98%
Parameters:     {'SVR_rbf__C': 5, 'SVR_rbf__max_iter': 500}
**********************************************************************
---------------------------- [SVR_linear] ----------------------------
Score:          64.07%
Parameters:     {'SVR_linear__C': 0.1, 'SVR_linear__max_iter': 500}
**********************************************************************
------------------------------ [Ridge] -------------------------------
Score:          63.98%
Parameters:     {'Ridge__alpha': 100, 'Ridge__max_iter': 200}
**********************************************************************
------------------------------ [Lasso] -------------------------------
Score:          60.36%
Parameters:     {'Lasso__alpha': 0.001, 'Lasso__max_iter': 1000}
**********************************************************************
--------------------------- [RandomForest] ---------------------------
Score:          44.01%
Parameters:     {'RandomForest__max_depth': 5, 'RandomForest__n_estimators': 100}
**********************************************************************

另外,不同的分组给出了非常不同的测试分数:

In [43]: clf = grid['SVR_linear']

In [44]: {k:v for k,v in clf.cv_results_.items() if k.endswith('_test_score')}
Out[44]:
{'mean_test_score': array([0.64067998, 0.63919104, 0.6391681 , 0.64067998, 0.63919104, 0.6391681 , 0.64067998, 0.63919104, 0.6391681 ]),
 'rank_test_score': array([1, 4, 7, 1, 4, 7, 1, 4, 7]),
 'split0_test_score': array([0.98557453, 0.98876705, 0.98883802, 0.98557453, 0.98876705, 0.98883802, 0.98557453, 0.98876705, 0.98883802]),
 'split1_test_score': array([0.69915178, 0.69750946, 0.69740475, 0.69915178, 0.69750946, 0.69740475, 0.69915178, 0.69750946, 0.69740475]),
 'split2_test_score': array([0.23568677, 0.22964765, 0.22961214, 0.23568677, 0.22964765, 0.22961214, 0.23568677, 0.22964765, 0.22961214]),
 'std_test_score': array([0.30903146, 0.31275403, 0.31278954, 0.30903146, 0.31275403, 0.31278954, 0.30903146, 0.31275403, 0.31278954])}

这是完整的代码:

import os
#import contextlib
from pathlib import Path
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import SGDRegressor, Ridge, Lasso
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.externals import joblib


def get_data_split(path='.'):
    p = Path(path)
    kwargs = dict(delim_whitespace=True, header=None)
    X_train = pd.read_csv(list(p.glob('trainX.txt*'))[0], **kwargs)
    y_train = pd.read_csv(list(p.glob('trainY.txt*'))[0], **kwargs)
    X_test = pd.read_csv(list(p.glob('testX.txt*'))[0], **kwargs)
    y_test = pd.read_csv(list(p.glob('testY.txt*'))[0], **kwargs)
    return X_train, y_train[0], X_test, y_test[0]


def get_data(path='.'):
    p = Path(path)
    kwargs = dict(delim_whitespace=True, header=None)
    X_train = pd.read_csv(list(p.glob('trainX.txt*'))[0], **kwargs)
    y_train = pd.read_csv(list(p.glob('trainY.txt*'))[0], **kwargs)
    X_test = pd.read_csv(list(p.glob('testX.txt*'))[0], **kwargs)
    y_test = pd.read_csv(list(p.glob('testY.txt*'))[0], **kwargs)
    return (pd.concat([X_train, X_test], ignore_index=True),
            pd.concat([y_train, y_test], ignore_index=True)[0])


def fit_all_classifiers_grid(X, y, classifiers, **common_grid_kwargs):
    grids = {}
    for clf in classifiers:
        print('{:-^70}'.format(' [' + clf['name'] + '] '))
        pipe = Pipeline([
                    ("scale", StandardScaler()),
                    (clf['name'], clf['clf'])   ])
        grids[clf['name']] = (GridSearchCV(pipe,
                                           param_grid=clf['param_grid'],
                                           **common_grid_kwargs)
                                  .fit(X, y))
        # saving single trained model ...
        joblib.dump(grids[clf['name']], './{}.pkl'.format(clf['name']))
    return grids


def test_dataset(grid, X_test, y_test):
    res = {}
    for name, clf in grid.items():
        y_pred = clf.predict(X_test)
        res[name] = {'MSE': mean_squared_error(y_test, y_pred),
                       'R2': r2_score(y_test, y_pred)
                      }
    return res


def print_grid_results(grids):
    for name, clf in grids.items():
        print('{:-^70}'.format(' [' + name + '] '))
        print('Score:\t\t{:.2%}'.format(clf.best_score_))
        print('Parameters:\t{}'.format(clf.best_params_))
        print('*' * 70)




classifiers = [
    {   'name':     'SVR_rbf',
        'clf':      SVR(),
        'title':    "SVR_rbf",
        'param_grid': {
            'SVR_rbf__C':           [0.1, 1, 5],
            'SVR_rbf__max_iter':    [500, 1000, 5000]
        } 
    },
    {   'name':     'SVR_linear',
        'clf':      SVR(kernel='linear'),
        'title':    "SVR_rbf",
        'param_grid': {
            'SVR_linear__C':           [0.1, 1, 5],
            'SVR_linear__max_iter':    [500, 1000, 5000]
        } 
    },
    {   'name':     'Ridge',
        'clf':      Ridge(),
        'title':    "Ridge",
        'param_grid': {
            'Ridge__alpha':         [0.1, 1, 5, 10, 50, 100],
            'Ridge__max_iter':      [200, 500]
        } 
    },
    {   'name':     'Lasso',
        'clf':      Lasso(),
        'title':    "Lasso",
        'param_grid':  {
            'Lasso__alpha':         [0.001, 0.01, 0.1, 1, 5, 10],
            'Lasso__max_iter':      [1000, 5000]
        } 
    },
    {   'name':     'RandomForest',
        'clf':      RandomForestRegressor(),
        'title':    "RandomForest",
        'param_grid':  {
            'RandomForest__n_estimators':   [10, 100],
            'RandomForest__max_depth':      [3, 5],
        } 
    },
]


def main(path):
    #path = r'D:\data\work\.ML\SO\49094242-SVM provided a bad result in my data'
    os.chdir(path)

    X, y = get_data(path)
    grid = fit_all_classifiers_grid(X, y, classifiers, cv=3, verbose=2, n_jobs=-1)
    print_grid_results(grid)

    #X_train, y_train, X_test, y_test = get_data_split(path)
    #grid = fit_all_classifiers_grid(X_train, y_train, classifiers, cv=2, verbose=2, n_jobs=-1)
    #res = test_dataset(grid, X_test, y_test)
    #print(res)

PS 很抱歉使用名称 classifier 而不是 regressor - 我只是重用了我正在寻找最佳分类器的旧代码....

【讨论】:

  • 非常感谢。你能告诉我如何使用给定的搜索参数实现对测试集的预测吗?我已经在 Ubuntu 中尝试过,但我无法运行它并出现错误 X_train = pd.read_csv(list(p.glob('trainX.txt*'))[0], **kwargs) IndexError: list index out of range
  • @Jame,你不必使用p.glob() - 你可以简单地传递一个完整的文件名 - 我用这种方式,因为我已经 GZipped 你的文件,我...不想让你和"trainX.txt.gz" 这样的名字混淆......
  • 谢谢。我已经成功运行了
  • @Jame, grid[classifier_name].predict(X_test)
  • @Jame,我可以在 5 到 6 小时内做一个例子,当我回家的时候......但是 100% - 看起来很可疑 - 我想它过度拟合了......你能提供你的更新数据吗套?
【解决方案3】:

根据您的数据集,您的特征似乎太高了。在开始使用 SVM 进行处理之前,最好使用特征分组算法。

【讨论】:

  • 您可以从下面的链接设置 scikitfeatureselection 并使用提供的算法。它包含超过 40 种算法。featureselection.asu.edu
  • 我已经通过了特征选择,结果如上特征。我不认为我必须再做一次
猜你喜欢
  • 2020-06-15
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 2021-05-29
  • 2014-06-30
  • 2022-07-13
  • 2013-11-14
  • 2012-08-23
相关资源
最近更新 更多