转载

kaggle数据挖掘竞赛初步--Titanic<随机森林&特征重要性>

特征工程系列:

Titanic系列之原始数据分析和数据处理

Titanic系列之数据变换

Titanic系列之派生属性&维归约

之前的三篇博文已经进行了一次还算完整的特征工程,分析字符串类型的变量获取新变量,对数值变量进行规范化,获取派生属性并进行维规约。现在我们已经有了一个特征集,可以进行训练模型了。

由于这是一个分类问题,可以使用L1 SVM 随机森林等分类算法,随机森林是一个非常简单而且实用的分类模型,可调的变量很少。它的一个非常重要的变量是树的个数,树的个数增加到一定大小后会使耗时加大,但是精度不会增加很多。

经过之前的特征工程,现在已经有237个特征,数目过多的特征会使模型过拟合,幸运的是,随机森林在训练之后可以产生一个各个特征重要性的数据集,我们可以利用这个数据集,确定一个阈值,选出来对模型训练帮助最大的一些属性,这里使用的随机森林的参数都是默认值。

 1     X = input_df.values[:, 1::]  2     y = input_df.values[:, 0]  3     survived_weight = .75  4     y_weights = np.array([survived_weight if s == 0 else 1 for s in y])  5   6     print "Rough fitting a RandomForest to determine feature importance..."  7     forest = RandomForestClassifier(oob_score=True, n_estimators=10000)  8     forest.fit(X, y, sample_weight=y_weights)  9     feature_importance = forest.feature_importances_ 10     feature_importance = 100.0 * (feature_importance / feature_importance.max()) 11  12     fi_threshold = 18     13     important_idx = np.where(feature_importance > fi_threshold)[0] 14     important_features = features_list[important_idx] 15     print "/n", important_features.shape[0], "Important features(>", / 16           fi_threshold, "% of max importance).../n"#, / 17             #important_features 18     sorted_idx = np.argsort(feature_importance[important_idx])[::-1] 19     #get the figure about important features 20     pos = np.arange(sorted_idx.shape[0]) + .5 21     plt.subplot(1, 2, 2) 22     plt.title('Feature Importance') 23     plt.barh(pos, feature_importance[important_idx][sorted_idx[::-1]], / 24             color='r',align='center') 25     plt.yticks(pos, important_features[sorted_idx[::-1]]) 26     plt.xlabel('Relative Importance') 27     plt.draw() 28     plt.show()

代码有点长,但主要分成两块,一是模型训练,二是根据训练得到的特征重要性筛选重要特征并画图。

得到的特征重要性大于18的属性如下图所示:

kaggle数据挖掘竞赛初步--Titanic&lt;随机森林&amp;特征重要性&gt;

可以看到Tiltle_Mr Title_id Gender这三个属性相当重要。而与Title有关的属性都是我们对姓名进行分析得到的,可见一些字符串属性中可能会藏有非常重要的信息,在特种工程中要非常重视而不是将其抛弃。因为我们的原始属性非常少,所以产生的重要属性大都是原始属性的数学组合,派生变量可能并不是必需的,这主要和模型有关,但大多数时候派生变量是没有什么坏处的。对于随机森林这种训练数据想对容易的模型来说,可能一些原始的属性直接用来进行训练也会产生很好的效果,但是作为一道学习题,当然是什么处理办法都要尝试一遍,积累经验啦。

对于随机森林如何得到变脸重要性的,可以看一下scikit learn 的官方文档 scikit-learn.org/stable/auto_examples/ensemble/plot_forest_importances.html#example-ensemble-plot-forest-importances-py

当然在得到重要的特征后,我们就要把不重要的特征去掉了,以提高模型的训练速度(阈值可调的小一点,以保留更多的特征)

1     X = X[:, important_idx][:, sorted_idx] 2     submit_df = submit_df.iloc[:,important_idx].iloc[:,sorted_idx]

现在我们就得到了最终的数据集,终于可以正式用来训练模型了。

上面部分都是用的随机森林的默认参数,但是模型的参数是可调的,我们要调整参数以获得更好的训练。scikit learn 提供了两种参数优化的方法,也是其他工具通用的方法,一是GridSearch,另一个是RandomizedSearch。 这两种情况下 ,都可以指定 每个参数 取值范围,创建一个字典 。将参数字典提供给search方法, 它就会 执行 模型 所指定的 值的组合 对于 GridSearch 它测试 参数 每一个 可能的组合 RandomizedSearch 允许指定 有多少 不同的组合 要测试 ,然后 随机选择 组合 如果 正在使用 模型 关键参数 很多, RandomizedSearch 很有用可以 帮助 节省时间

 1 sqrtfeat = int(np.sqrt(X.shape[1]))  2 minsampsplit = int(X.shape[0]*0.015)  3 # (adapted from http://scikit-learn.org/stable/auto_examples/randomized_search.html)  4 def report(grid_scores, n_top=5):  5     params = None  6     top_scores = sorted(grid_scores, key=itemgetter(1), reverse=True)[:n_top]  7     for i, score in enumerate(top_scores):  8         print("Parameters with rank: {0}".format(i + 1))  9         print("Mean validation score: {0:.4f} (std: {1:.4f})".format( 10               score.mean_validation_score, np.std(score.cv_validation_scores))) 11         print("Parameters: {0}".format(score.parameters)) 12         print("") 13          14         if params == None: 15             params = score.parameters 16      17     return params 18 # Simple grid test 19 grid_test1 = { "n_estimators"      : [1000, 2500, 5000], 20                "criterion"         : ["gini", "entropy"], 21                "max_features"      : [sqrtfeat-1, sqrtfeat, sqrtfeat+1], 22                "max_depth"         : [5, 10, 25], 23                "min_samples_split" : [2, 5, 10,minsampsplit ] } 24  25 forest = RandomForestClassifier(oob_score=True) 26   27 print "Hyperparameter optimization using GridSearchCV..." 28 grid_search = GridSearchCV(forest, grid_test1, n_jobs=-1, cv=10) 29 grid_search.fit(X, y) 30 best_params_from_grid_search = scorereport.report(grid_search.grid_scores_)

经训练得到的参数为    params_score = { "n_estimators"      : 10000,   "max_features"      : sqrtfeat,   "min_samples_split" : minsampsplit },结果还是很符合经验结果预测的。

怎么评价这个训练后的模型呢? Learning Curves。《机器学习实战》这本书里有讲,Andrew Ng的公开课里也讲过。主要是偏差方差折衷与测试误差和训练误差的关系。我们应该调整模型来达到测试误差的最小值。 sklearn . learning_curve模块可以完成这个功能。 Learning Curves曲线最后表明我们的模型需要更多的数据训练。

在训练时要注意的是,因为幸存者相对未幸存的人数较少,所以数据是不均衡的,可以通过上抽样或下抽样或者调整样本的权重,来获得均衡的训练样本。

然后我们就可以用forest来预测测试集了,bingo!

正文到此结束
Loading...