Kaggle房价预测比赛

前言:最近开始kaggle的一些竞赛,从一开始的懵懵懂懂,到后面的逐渐熟练,在kaggle上真的学到了很多,特此将自己的一些想法与思考记录下来,希望能和大家一起探讨学习,如果有不对的地方,希望大家可以指出来!

赛题描述:要求购房者描述他们梦dream以求的房子,他们可能不会从地下室天花板的高度或与东西方铁路的距离开始。但是,这场运动会比赛的数据集证明,与价格或卧室或白色栅栏的数量相比,影响价格谈判的因素更多。借助79个解释性变量(几乎)描述了爱荷华州埃姆斯市住宅的方方面面,本次竞赛要求您预测每个房屋的最终价格。链接
这是kaggle新手入门的一道题目,对于初入数据挖掘的同学来说,可以说难度不是很大,只要学过机器学习,熟悉常用的算法工具,例如各种回归算法以及随机森林等树结构的算法,还有pandas以及sklearn的工具使用,那么我们都会得到一个不错的结果。然而如何将成绩进一步的提高,模型的相关优化,是比较困难的,特别是对于我们新手来说,完全就是没有任何的思路。我在kaggle上学习了大神一些的技术方法之后,受益颇多,想在这里将自己的思考记录下来。

比赛流程

总结:对于数据挖掘比赛来说,特征工程是一个比较重要的环节,在训练模型之前,我们需要花费大量的时间精力进行特征工程(包括数据预处理,特征的构造,特征融合以及特征筛选),好的数据处理,会影响后续的训练结果,之前听过这样一句话:“特征工程决定了上限”(忘了是谁说的了。。。)特征构造好了,后续的模型结构我们根据任务场景以及数据的特点进行选择————比如说,常见的回归模型:lasso回归,逻辑回归,KernelRidge等;树结构模型:随机森林,Adaboost,xgboost,lightgbm;SVC,SVM等等。如果考虑数据特点的话,线性回归模型受数据大小影响较大,而树结构是根据特征属性进行分类,鲁棒性较好。当然,我们可以同时考虑这些模型,在后期,可以对模型进行融合,可以进一步提高自己的成绩。

对于整体的流程,我大致分为了这些:

  • 赛题的审读以及数据的分析:
    • 对比赛题目的阅读,包括业务背景,赛题任务,问题的定义,数据产生的来源(对数据缺失是随机还是非随机性的分析有一定的帮助),是否有类似的比赛或者学术任务可以借鉴
    • 数据字段属性的含义,每个字段的数据类型,每个字段属性的数据分布,数据是否有缺失,观察数据是否有离群值以及噪音
      注意:对于数据的分析,一定要使用绘图工具进行可视化的分析,这样有助于自己对于整体数据特点的把握,为后续的特征构造提供一些思路(强烈推荐seaborn,用过之后感觉真香😎😎)
  • 数据的预处理
    • 对缺失值的处理:目前来说,我所见到的常用缺失值的处理主要有,频次最高数据填充,平均值填充,中值填充或者直接填充0。网上一些资料说可以直接将缺失值丢弃,我没有试过,但是我觉得这样会造成数据的浪费,如果是随机性的缺失,可能不会带来影响,而非随机性的数据缺失,影响可能会比较大。还有一种用其他变量,通过构造训练模型的方式进行缺失值的填充。
    • 数据异常:在观察了数据可视化的图形之后,我们可以发现一些不合常理的数据,可以直接删除
    • 数据分布问题:在kaggle上,有人对目标变量的分布进行了分析,并与其正态分布进行了比较,之后通过log(1+x)方法对数据进行了处理,由于线性回归是基于正态分布的前提假设,所以对其进行统计分析时,需经过数据的转换,使得数据符合正态分布。
    • 数据编码:对于类别型的特征变量,需要对其进行一定的编码,转换成可进行运算的数值,常见的有Label encoder(适用于具有排序意义的变量), one-hot encoder。当然,如果只考虑树结构模型,Label encoder是足够的,而且占用空间小。
      注意:我的教训就是,对数据预处理一定要将训练集和测试集合并在一起操作,避免重复操作,同时减少编码出问题,导致训练集特征数量和测试集不一样😢😢😢!!!
  • 特征的构造
  • 模型训练及测试
    • sklearn工具包集成了很多常见的模型,以及CV交叉验证。初始之时,采用多个单模型进行CV训练,观察哪些模型的效果比较好,将其作为base 模型
    • 使用Pipline可以很方便的将标准化与模型结合起来,大大方便了模型的训练——对于线性回归模型来说,标准化可以提高精度以及训练的速度
  • 模型的融合(重中之重!)
    • 在这里,大神给出了两种模型融合的方案,看完之后觉得超级牛x
class AveragingModels(BaseEstimator, RegressorMixin, TransformerMixin): # 相当于构造了一个新的estimator,并做回归的任务
    def __init__(self, models):
        self.models = models

    # we define clones of the original models to fit the data in
    def fit(self, X, y):
        self.models_ = [clone(x) for x in self.models]

        # Train cloned base models
        for model in self.models_:
            model.fit(X, y)

        return self

    # Now we do the predictions for cloned models and average them
    def predict(self, X):
        predictions = np.column_stack([
            model.predict(X) for model in self.models_
        ])
        return np.mean(predictions, axis=1)

这里构造了一种简单基础模型堆叠平均模型,即将基础模型的预测值作了平均作为最终的预测值。这里比较新颖的是,使用类构造一种新的估算器。
- 第二种方案,在第一种的基础上,增加了元模型,即将基础模型进行CV训练,将基础模型对测试集的预测再作为元模型的输入特征(比如有4个基础模型,样本数量为N,那么元模型的输入数据就是N*4),并与目标值进行训练,最终以元模型的预测结果作为最终结果。

class StackingAveragedModels(BaseEstimator, RegressorMixin, TransformerMixin):
    def __init__(self, base_models, meta_model, n_folds=5):
        self.base_models = base_models
        self.meta_model = meta_model
        self.n_folds = n_folds

    # We again fit the data on clones of the original models
    def fit(self, X, y):
        self.base_models_ = [list() for x in self.base_models]
        self.meta_model_ = clone(self.meta_model)
        kfold = KFold(n_splits=self.n_folds, shuffle=True, random_state=156)

        # Train cloned base models then create out-of-fold predictions
        # that are needed to train the cloned meta-model
        out_of_fold_predictions = np.zeros((X.shape[0], len(self.base_models)))
        for i, model in enumerate(self.base_models):
            for train_index, holdout_index in kfold.split(X, y):
                instance = clone(model)
                self.base_models_[i].append(instance)
                instance.fit(X[train_index], y[train_index])
                y_pred = instance.predict(X[holdout_index])
                out_of_fold_predictions[holdout_index, i] = y_pred

        # Now train the cloned  meta-model using the out-of-fold predictions as new feature
        self.meta_model_.fit(out_of_fold_predictions, y)
        return self

    # Do the predictions of all base models on the test data and use the averaged predictions as
    # meta-features for the final prediction which is done by the meta-model
    def predict(self, X):
        meta_features = np.column_stack([
            np.column_stack([model.predict(X) for model in base_models]).mean(axis=1)
            for base_models in self.base_models_])
        return self.meta_model_.predict(meta_features)

总结

在这里,我只将我在其中遇到的一些关键东西列举了出来,详细的可以在官网上一些分享的资料进行学习。对自己的整个过程进行了梳理,我觉得还可以在特征构造,以及模型训练过程中的一些参数的调整,像自动寻参的方法进行更多的工作。

参考资料

https://www.cnblogs.com/king-lps/p/7843395.html
https://www.cnblogs.com/wzdLY/p/9656420.html
https://blog.csdn.net/ICERON/article/details/80243198
https://www.jianshu.com/p/c532424541ad
https://blog.csdn.net/wateryouyo/article/details/53909636
https://wenku.baidu.com/view/96140c8376a20029bd642de3.html
http://blog.sina.com.cn/s/blog_5eb5c9370102vyim.html

posted @ 2020-03-10 21:36  青衣素  阅读(710)  评论(0)    收藏  举报