十三、树和森林

作者:Chris Albon

译者:飞龙

协议:CC BY-NC-SA 4.0

Adaboost 分类器

十三、树和森林 - 图1

  1. # 加载库
  2. from sklearn.ensemble import AdaBoostClassifier
  3. from sklearn import datasets
  4. # 加载数据
  5. iris = datasets.load_iris()
  6. X = iris.data
  7. y = iris.target

最重要的参数是base_estimatorn_estimatorslearning_rate

  • base_estimator是用于训练弱模型的学习算法。 这几乎总是不需要改变,因为到目前为止,与 AdaBoost 一起使用的最常见的学习者是决策树 - 这个参数的默认参数。
  • n_estimators是迭代式训练的模型数。
  • learning_rate是每个模型对权重的贡献,默认为1。 降低学习率将意味着权重将增加或减少到很小的程度,迫使模型训练更慢(但有时会产生更好的表现得分)。
  • lossAdaBoostRegressor独有的,它设置了更新权重时使用的损失函数。 这默认为线性损失函数,但可以更改为squareexponential
  1. # 创建 adaboost 决策树分类器对象
  2. clf = AdaBoostClassifier(n_estimators=50,
  3. learning_rate=1,
  4. random_state=0)
  5. # 训练模型
  6. model = clf.fit(X, y)

决策树分类器

十三、树和森林 - 图2

  1. # 加载库
  2. from sklearn.tree import DecisionTreeClassifier
  3. from sklearn import datasets
  4. # 加载数据
  5. iris = datasets.load_iris()
  6. X = iris.data
  7. y = iris.target
  8. # 创建使用 GINI 的决策树分类器对象
  9. clf = DecisionTreeClassifier(criterion='gini', random_state=0)
  10. # 训练模型
  11. model = clf.fit(X, y)
  12. # 生成新的观测
  13. observation = [[ 5, 4, 3, 2]]
  14. # 预测观测的类别
  15. model.predict(observation)
  16. # array([1])
  17. # 查看三个类别的预测概率
  18. model.predict_proba(observation)
  19. # array([[ 0., 1., 0.]])

决策树回归

十三、树和森林 - 图3

  1. # 加载库
  2. from sklearn.tree import DecisionTreeRegressor
  3. from sklearn import datasets
  4. # 加载只有两个特征的数据
  5. boston = datasets.load_boston()
  6. X = boston.data[:,0:2]
  7. y = boston.target

决策树回归的工作方式类似于决策树分类,但不是减少基尼杂质或熵,而是测量潜在的分割点,它们减少均方误差(MSE)的程度:

十三、树和森林 - 图4

其中 十三、树和森林 - 图5 是目标的真实值,十三、树和森林 - 图6 是预测值。

  1. # 创建决策树回归器对象
  2. regr = DecisionTreeRegressor(random_state=0)
  3. # 训练模型
  4. model = regr.fit(X, y)
  5. # 生成新的观测
  6. observation = [[0.02, 16]]
  7. # 预测观测的值
  8. model.predict(observation)
  9. # array([ 33.])

特征的重要性

十三、树和森林 - 图7

  1. # 加载库
  2. from sklearn.ensemble import RandomForestClassifier
  3. from sklearn import datasets
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. # 加载数据
  7. iris = datasets.load_iris()
  8. X = iris.data
  9. y = iris.target
  10. # 创建决策树分类器对象
  11. clf = RandomForestClassifier(random_state=0, n_jobs=-1)
  12. # 训练模型
  13. model = clf.fit(X, y)
  14. # 计算特征重要性
  15. importances = model.feature_importances_
  16. # 对特征重要性降序排序
  17. indices = np.argsort(importances)[::-1]
  18. # 重新排列特征名称,使它们匹配有序的特征重要性
  19. names = [iris.feature_names[i] for i in indices]
  20. # 创建绘图
  21. plt.figure()
  22. # 创建绘图标题
  23. plt.title("Feature Importance")
  24. # 添加条形
  25. plt.bar(range(X.shape[1]), importances[indices])
  26. # 添加特征名称作为 x 轴标签
  27. plt.xticks(range(X.shape[1]), names, rotation=90)
  28. # 展示绘图
  29. plt.show()

png

使用随机森林的特征选择

通常在数据科学中,我们有数百甚至数百万个特征,我们想要一种方法来创建仅包含最重要特征的模型。 这有三个好处。 首先,我们使模型更易于解释。 其次,我们可以减少模型的方差,从而避免过拟合。 最后,我们可以减少训练模型的计算开销(和时间)。 仅识别最相关特征的过程称为“特征选择”。

数据科学工作流程中,随机森林通常用于特征选择。 原因是,随机森林使用的基于树的策略,自然按照它们如何改善节点的纯度来排序。 这意味着所有树的不纯度的减少(称为基尼不纯度)。 不纯度减少最多的节点出现在树的开始处,而不纯度减少最少的节点出现在树的末端。 因此,通过在特定节点下修剪树,我们可以创建最重要特征的子集。

在这个教程中,我们将要:

  • 准备数据集
  • 训练随机森林分类器
  • 识别最重要的特征
  • 创建新的“有限特征的”数据集,仅仅包含那些特征
  • 在新数据集上训练第二个分类器
  • 将“全部特征的”分类器的准确率,和“有限特征的”分类器比较

注:还有其他重要定义,但在本教程中,我们将讨论限制为基尼重要性。

  1. import numpy as np
  2. from sklearn.ensemble import RandomForestClassifier
  3. from sklearn import datasets
  4. from sklearn.model_selection import train_test_split
  5. from sklearn.feature_selection import SelectFromModel
  6. from sklearn.metrics import accuracy_score

本教程中使用的数据集是着名的鸢尾花数据集鸢尾花数据包含来自三种鸢尾y和四个特征变量X的 50 个样本。

  1. # 加载鸢尾花数据集
  2. iris = datasets.load_iris()
  3. # 创建特征名称列表
  4. feat_labels = ['Sepal Length','Sepal Width','Petal Length','Petal Width']
  5. # 从特征中创建 X
  6. X = iris.data
  7. # 从目标中创建 y
  8. y = iris.target
  9. # 查看特征
  10. X[0:5]
  11. '''
  12. array([[ 5.1, 3.5, 1.4, 0.2],
  13. [ 4.9, 3\. , 1.4, 0.2],
  14. [ 4.7, 3.2, 1.3, 0.2],
  15. [ 4.6, 3.1, 1.5, 0.2],
  16. [ 5\. , 3.6, 1.4, 0.2]])
  17. '''
  18. # 查看目标数据
  19. y
  20. '''
  21. array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  22. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  23. 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  24. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  25. 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  26. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  27. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
  28. '''
  29. # 将数据分为 40% 的测试和 60% 的训练集
  30. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)
  31. # 创建随机森林分类器
  32. clf = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1)
  33. # 训练分类器
  34. clf.fit(X_train, y_train)
  35. # 打印每个特征的名称和基尼重要性
  36. for feature in zip(feat_labels, clf.feature_importances_):
  37. print(feature)
  38. '''
  39. ('Sepal Length', 0.11024282328064565)
  40. ('Sepal Width', 0.016255033655398394)
  41. ('Petal Length', 0.45028123999239533)
  42. ('Petal Width', 0.42322090307156124)
  43. '''

上面的得分是每个变量的重要性得分。 有两点需要注意。 首先,所有重要性得分加起来为 100%。 其次,“花瓣长度”和“花瓣宽度”远比其他两个特征重要。结合起来,“花瓣长度”和“花瓣宽度”的重要性约为 0.86!显然,这些是最重要的特征。

  1. # 创建一个选择器对象,
  2. # 该对象将使用随机森林分类器来标识重要性大于 0.15 的特征
  3. sfm = SelectFromModel(clf, threshold=0.15)
  4. # 训练选择器
  5. sfm.fit(X_train, y_train)
  6. '''
  7. SelectFromModel(estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
  8. max_depth=None, max_features='auto', max_leaf_nodes=None,
  9. min_impurity_split=1e-07, min_samples_leaf=1,
  10. min_samples_split=2, min_weight_fraction_leaf=0.0,
  11. n_estimators=10000, n_jobs=-1, oob_score=False, random_state=0,
  12. verbose=0, warm_start=False),
  13. prefit=False, threshold=0.15)
  14. '''
  15. # 打印最重要的特征的名称
  16. for feature_list_index in sfm.get_support(indices=True):
  17. print(feat_labels[feature_list_index])
  18. '''
  19. Petal Length
  20. Petal Width
  21. '''
  22. # 转换数据来创建仅包含最重要特征的新数据集
  23. # 注意:我们必须将变换应用于训练 X 和测试 X 数据。
  24. X_important_train = sfm.transform(X_train)
  25. X_important_test = sfm.transform(X_test)
  26. # 为最重要的特征创建新的随机森林分类器
  27. clf_important = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1)
  28. # 在包含最重要特征的新数据集上训练新分类器
  29. clf_important.fit(X_important_train, y_train)
  30. '''
  31. RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
  32. max_depth=None, max_features='auto', max_leaf_nodes=None,
  33. min_impurity_split=1e-07, min_samples_leaf=1,
  34. min_samples_split=2, min_weight_fraction_leaf=0.0,
  35. n_estimators=10000, n_jobs=-1, oob_score=False, random_state=0,
  36. verbose=0, warm_start=False)
  37. '''
  38. # 将全部特征的分类器应用于测试数据
  39. y_pred = clf.predict(X_test)
  40. # 查看我们的全部特征(4 个特征)的模型的准确率
  41. accuracy_score(y_test, y_pred)
  42. # 0.93333333333333335
  43. # 将全部特征的分类器应用于测试数据
  44. y_important_pred = clf_important.predict(X_important_test)
  45. # 查看我们有限特征(2 个特征)的模型的准确率
  46. accuracy_score(y_test, y_important_pred)
  47. # 0.8833333333333333

从准确率得分可以看出,包含所有四个特征的原始模型准确率为 93.3%,而仅包含两个特征的“有限”模型准确率为 88.3%。 因此,为了精确率的低成本,我们将模型中的特征数量减半。

在随机森林中处理不平衡类别

  1. # 加载库
  2. from sklearn.ensemble import RandomForestClassifier
  3. import numpy as np
  4. from sklearn import datasets
  5. # 加载数据
  6. iris = datasets.load_iris()
  7. X = iris.data
  8. y = iris.target
  9. # 通过移除前 40 个观测,生成高度不平衡的类别
  10. X = X[40:,:]
  11. y = y[40:]
  12. # 创建目标向量,表示类别是否为 0
  13. y = np.where((y == 0), 0, 1)

当使用RandomForestClassifier时,有用的设置是class_weight = balanced,其中类自动加权,与它们在数据中出现的频率成反比。具体来说:

十三、树和森林 - 图9

其中 十三、树和森林 - 图10 是类 十三、树和森林 - 图11 的权重,十三、树和森林 - 图12 是观测数,十三、树和森林 - 图13 是类 十三、树和森林 - 图14 中的观测数,十三、树和森林 - 图15 是类的总数。

  1. # 创建决策树分类器对象
  2. clf = RandomForestClassifier(random_state=0, n_jobs=-1, class_weight="balanced")
  3. # 训练模型
  4. model = clf.fit(X, y)

随机森林分类器

  1. # 加载库
  2. from sklearn.ensemble import RandomForestClassifier
  3. from sklearn import datasets
  4. # 加载数据
  5. iris = datasets.load_iris()
  6. X = iris.data
  7. y = iris.target
  8. # 创建使用熵的随机森林分类器
  9. clf = RandomForestClassifier(criterion='entropy', random_state=0, n_jobs=-1)
  10. # 训练模型
  11. model = clf.fit(X, y)
  12. # 创建新的观测
  13. observation = [[ 5, 4, 3, 2]]
  14. # 预测观测的类别
  15. model.predict(observation)
  1. array([1])

随机森林分类器示例

本教程基于 Yhat 2013 年的[ Python 中的随机森林]教程(http://blog.yhat.com/posts/random-forests-in-python.html)。 如果你想要随机森林的理论和用途的总结,我建议你查看他们的指南。 在下面的教程中,我对文章末尾提供的随机森林的简短代码示例进行了注释,更正和扩展。 具体来说,我(1)更新代码,使其在最新版本的 pandas 和 Python 中运行,(2)编写详细的注释,解释每个步骤中发生的事情,以及(3)以多种方式扩展代码。

让我们开始吧!

数据的注解

本教程的数据很有名。 被称为鸢尾花数据集,它包含四个变量,测量了三个鸢尾花物种的各个部分,然后是带有物种名称的第四个变量。 它在机器学习和统计社区中如此着名的原因是,数据需要很少的预处理(即没有缺失值,所有特征都是浮点数等)。

  1. # 加载鸢尾花数据集
  2. from sklearn.datasets import load_iris
  3. # 加载 sklearn 的随机森林分类器
  4. from sklearn.ensemble import RandomForestClassifier
  5. # 加载 pandas
  6. import pandas as pd
  7. # 加载 numpy
  8. import numpy as np
  9. # 设置随机种子
  10. np.random.seed(0)
  11. # Create an object called iris with the iris data
  12. iris = load_iris()
  13. # 创建带有四个特征变量的数据帧
  14. df = pd.DataFrame(iris.data, columns=iris.feature_names)
  15. # 查看前五行
  16. df.head()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
05.13.51.40.2
14.93.01.40.2
24.73.21.30.2
34.63.11.50.2
45.03.61.40.2
  1. # 添加带有物种名称的新列,我们要尝试预测它
  2. df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
  3. # 查看前五行
  4. df.head()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)species
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa
  1. # 创建一个新列,每列生成一个0到1之间的随机数,
  2. # 如果该值小于或等于.75,则将该单元格的值设置为 True
  3. # 否则为 False。这是一种简洁方式,
  4. # 随机分配一些行作为训练数据,一些作为测试数据。
  5. df['is_train'] = np.random.uniform(0, 1, len(df)) <= .75
  6. # 查看前五行
  7. df.head()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)speciesis_train
05.13.51.40.2setosaTrue
14.93.01.40.2setosaTrue
24.73.21.30.2setosaTrue
34.63.11.50.2setosaTrue
45.03.61.40.2setosaTrue
  1. # 创建两个新的数据帧,一个包含训练行,另一个包含测试行
  2. train, test = df[df['is_train']==True], df[df['is_train']==False]
  3. # 显示测试和训练数据帧的观测数
  4. print('Number of observations in the training data:', len(train))
  5. print('Number of observations in the test data:',len(test))
  6. '''
  7. Number of observations in the training data: 118
  8. Number of observations in the test data: 32
  9. '''
  10. # 创建特征列名称的列表
  11. features = df.columns[:4]
  12. # 查看特征
  13. features
  14. '''
  15. Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',
  16. 'petal width (cm)'],
  17. dtype='object')
  18. '''
  19. # train['species'] 包含实际的物种名称。
  20. # 在我们使用它之前,我们需要将每个物种名称转换为数字。
  21. # 因此,在这种情况下,有三种物种,它们被编码为 0, 1 或 2。
  22. y = pd.factorize(train['species'])[0]
  23. # 查看目标
  24. y
  25. '''
  26. array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  27. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  28. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  29. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  30. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  31. 2, 2, 2])
  32. '''
  33. # 创建随机森林分类器。按照惯例,clf 表示“分类器”
  34. clf = RandomForestClassifier(n_jobs=2, random_state=0)
  35. # 训练分类器,来接受训练特征
  36. # 并了解它们与训练集 y(物种)的关系
  37. clf.fit(train[features], y)
  38. '''
  39. RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
  40. max_depth=None, max_features='auto', max_leaf_nodes=None,
  41. min_impurity_split=1e-07, min_samples_leaf=1,
  42. min_samples_split=2, min_weight_fraction_leaf=0.0,
  43. n_estimators=10, n_jobs=2, oob_score=False, random_state=0,
  44. verbose=0, warm_start=False)
  45. '''

好哇! 我们做到了! 我们正式训练了我们的随机森林分类器! 现在让我们玩玩吧。 分类器模型本身存储在clf变量中。

如果你一直跟着,你会知道我们只在部分数据上训练了我们的分类器,留出了剩下的数据。 在我看来,这是机器学习中最重要的部分。 为什么? 因为省略了部分数据,我们有一组数据来测试我们模型的准确率!

让我们现在实现它。

  1. # 将我们训练的分类器应用于测试数据
  2. # (记住,以前从未见过它)
  3. clf.predict(test[features])
  4. '''
  5. array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2,
  6. 2, 2, 2, 2, 2, 2, 2, 2, 2])
  7. '''

你在上面看到什么? 请记住,我们将三种植物中的每一种编码为 0, 1 或 2。 以上数字列表显示,我们的模型基于萼片长度,萼片宽度,花瓣长度和花瓣宽度,预测每种植物的种类。 分类器对于每种植物有多自信? 我们也可以看到。

  1. # 查看前 10 个观测值的预测概率
  2. clf.predict_proba(test[features])[0:10]
  3. '''
  4. array([[ 1\. , 0\. , 0\. ],
  5. [ 1\. , 0\. , 0\. ],
  6. [ 1\. , 0\. , 0\. ],
  7. [ 1\. , 0\. , 0\. ],
  8. [ 1\. , 0\. , 0\. ],
  9. [ 1\. , 0\. , 0\. ],
  10. [ 1\. , 0\. , 0\. ],
  11. [ 0.9, 0.1, 0\. ],
  12. [ 1\. , 0\. , 0\. ],
  13. [ 1\. , 0\. , 0\. ]])
  14. '''

有三种植物,因此[1, 0, 0]告诉我们分类器确定植物是第一类。 再举一个例子,[0.9, 0.1, 0]告诉我们,分类器给出植物属于第一类的概率为90%,植物属于第二类的概率为 10%。 因为 90 大于 10,分类器预测植物是第一类。

现在我们已经预测了测试数据中所有植物的种类,我们可以比较我们预测的物种与该植物的实际物种。

  1. # 为每个预测的植物类别
  2. # 创建植物的实际英文名称
  3. preds = iris.target_names[clf.predict(test[features])]
  4. # 查看前五个观测值的预测物种
  5. preds[0:5]
  6. '''
  7. array(['setosa', 'setosa', 'setosa', 'setosa', 'setosa'],
  8. dtype='<U10')
  9. '''
  10. # 查看前五个观测值的实际物种
  11. test['species'].head()
  12. '''
  13. 7 setosa
  14. 8 setosa
  15. 10 setosa
  16. 13 setosa
  17. 17 setosa
  18. Name: species, dtype: category
  19. Categories (3, object): [setosa, versicolor, virginica]
  20. '''

看起来很不错! 至少对于前五个观测。 现在让我们看看所有数据。

混淆矩阵可能令人混淆,但它实际上非常简单。 列是我们为测试数据预测的物种,行是测试数据的实际物种。 因此,如果我们选取最上面的行,我们可以完美地预测测试数据中的所有 13 个山鸢尾。 然而,在下一行中,我们正确地预测了 5 个杂色鸢尾,但错误地将两个杂色鸢尾预测为维吉尼亚鸢尾。

混淆矩阵的简短解释方式是:对角线上的任何东西都被正确分类,对角线之外的任何东西都被错误地分类。

  1. # 创建混淆矩阵
  2. pd.crosstab(test['species'], preds, rownames=['Actual Species'], colnames=['Predicted Species'])
Predicted Speciessetosaversicolorvirginica
Actual Species
setosa1300
versicolor052
virginica0012

虽然我们没有像 OLS 那样得到回归系数,但我们得到的分数告诉我们,每个特征在分类中的重要性。 这是随机森林中最强大的部分之一,因为我们可以清楚地看到,在分类中花瓣宽度比萼片宽度更重要。

  1. # 查看特征列表和它们的重要性得分
  2. list(zip(train[features], clf.feature_importances_))
  3. '''
  4. [('sepal length (cm)', 0.11185992930506346),
  5. ('sepal width (cm)', 0.016341813006098178),
  6. ('petal length (cm)', 0.36439533040889194),
  7. ('petal width (cm)', 0.5074029272799464)]
  8. '''

随机森林回归

  1. # 加载库
  2. from sklearn.ensemble import RandomForestRegressor
  3. from sklearn import datasets
  4. # 加载只有两个特征的数据
  5. boston = datasets.load_boston()
  6. X = boston.data[:,0:2]
  7. y = boston.target
  8. # Create decision tree classifer object
  9. regr = RandomForestRegressor(random_state=0, n_jobs=-1)
  10. # 训练模型
  11. model = regr.fit(X, y)

在随机森林中选择特征重要性

  1. # 加载库
  2. from sklearn.ensemble import RandomForestClassifier
  3. from sklearn import datasets
  4. from sklearn.feature_selection import SelectFromModel
  5. # 加载数据
  6. iris = datasets.load_iris()
  7. X = iris.data
  8. y = iris.target
  9. # 创建随机森林分类器
  10. clf = RandomForestClassifier(random_state=0, n_jobs=-1)

数字越大,特征越重要(所有重要性得分总和为1)。 通过绘制这些值,我们可以为随机森林模型添加可解释性。

  1. # 创建选择重要性大于或等于阈值的特征的对象
  2. selector = SelectFromModel(clf, threshold=0.3)
  3. # 使用选择器生成新的特征矩阵
  4. X_important = selector.fit_transform(X, y)
  5. # 查看特征的前五个观测
  6. X_important[0:5]
  7. '''
  8. array([[ 1.4, 0.2],
  9. [ 1.4, 0.2],
  10. [ 1.3, 0.2],
  11. [ 1.5, 0.2],
  12. [ 1.4, 0.2]])
  13. '''
  14. # 使用最重要的特征训练随机森林
  15. model = clf.fit(X_important, y)

泰坦尼克比赛和随机森林

  1. import pandas as pd
  2. import numpy as np
  3. from sklearn import preprocessing
  4. from sklearn.ensemble import RandomForestClassifier
  5. from sklearn.model_selection import GridSearchCV, cross_val_score
  6. import csv as csv

你可以在 Kaggle 获取数据。

  1. # 加载数据
  2. train = pd.read_csv('data/train.csv')
  3. test = pd.read_csv('data/test.csv')
  4. # 创建特征列表,我们最终会接受他们
  5. features = ['Age', 'SibSp','Parch','Fare','male','embarked_Q','embarked_S','Pclass_2', 'Pclass_3']

性别

在这里,我们将性别标签(malefemale)转换为虚拟变量(10)。

  1. # 创建编码器
  2. sex_encoder = preprocessing.LabelEncoder()
  3. # 使编码器拟合训练数据,因此它知道 male = 1
  4. sex_encoder.fit(train['Sex'])
  5. # 将编码器应用于训练数据
  6. train['male'] = sex_encoder.transform(train['Sex'])
  7. # 将编码器应用于测试数据
  8. test['male'] = sex_encoder.transform(test['Sex'])
  9. # 使用单热编码,将编码的特征转换为虚拟值
  10. # 去掉第一个类别来防止共线性
  11. train_embarked_dummied = pd.get_dummies(train["Embarked"], prefix='embarked', drop_first=True)
  12. # 使用单热编码
  13. # 将“已编码”的测试特征转换为虚拟值
  14. # 去掉第一个类别来防止共线性
  15. test_embarked_dummied = pd.get_dummies(test["Embarked"], prefix='embarked', drop_first=True)
  16. # 将虚拟值的数据帧与主数据帧连接起来
  17. train = pd.concat([train, train_embarked_dummied], axis=1)
  18. test = pd.concat([test, test_embarked_dummied], axis=1)
  19. # 使用单热编码将 Pclass 训练特征转换为虚拟值
  20. # 去掉第一个类别来防止共线性
  21. train_Pclass_dummied = pd.get_dummies(train["Pclass"], prefix='Pclass', drop_first=True)
  22. # 使用单热编码将 Pclass 测试特征转换为虚拟值
  23. # 去掉第一个类别来防止共线性
  24. test_Pclass_dummied = pd.get_dummies(test["Pclass"], prefix='Pclass', drop_first=True)
  25. # 将虚拟值的数据帧与主数据帧连接起来
  26. train = pd.concat([train, train_Pclass_dummied], axis=1)
  27. test = pd.concat([test, test_Pclass_dummied], axis=1)

年龄

Age特征的许多值都缺失,并且会妨碍随机森林进行训练。 我们解决这个问题,我们将用年龄的平均值填充缺失值(一个实用的操作)。

  1. # 创建填充器对象
  2. age_imputer = preprocessing.Imputer(missing_values='NaN', strategy='mean', axis=0)
  3. # 将填充器对象拟合训练数据
  4. age_imputer.fit(train['Age'].reshape(-1, 1))
  5. # 将填充器对象应用于训练和测试数据
  6. train['Age'] = age_imputer.transform(train['Age'].reshape(-1, 1))
  7. test['Age'] = age_imputer.transform(test['Age'].reshape(-1, 1))
  8. # 创建填充器对象
  9. fare_imputer = preprocessing.Imputer(missing_values='NaN', strategy='mean', axis=0)
  10. # 将填充器对象拟合训练数据
  11. fare_imputer.fit(train['Fare'].reshape(-1, 1))
  12. # 将填充器对象应用于训练和测试数据
  13. train['Fare'] = fare_imputer.transform(train['Fare'].reshape(-1, 1))
  14. test['Fare'] = fare_imputer.transform(test['Fare'].reshape(-1, 1))
  15. # 创建包含参数所有候选值的字典
  16. parameter_grid = dict(n_estimators=list(range(1, 5001, 1000)),
  17. criterion=['gini','entropy'],
  18. max_features=list(range(1, len(features), 2)),
  19. max_depth= [None] + list(range(5, 25, 1)))
  20. # 创建随机森林对象
  21. random_forest = RandomForestClassifier(random_state=0, n_jobs=-1)
  22. # 创建网格搜索对象,使用 5 倍交叉验证
  23. # 并使用所有核(n_jobs = -1)
  24. clf = GridSearchCV(estimator=random_forest, param_grid=parameter_grid, cv=5, verbose=1, n_jobs=-1)
  25. # 将网格搜索嵌套在 3 折 CV 中来进行模型评估
  26. cv_scores = cross_val_score(clf, train[features], train['Survived'])
  27. # 打印结果
  28. print('Accuracy scores:', cv_scores)
  29. print('Mean of score:', np.mean(cv_scores))
  30. print('Variance of scores:', np.var(cv_scores))
  31. # 在整个数据集上重新训练模型
  32. clf.fit(train[features], train['Survived'])
  33. # 预测在测试数据集中的幸存者
  34. predictions = clf.predict(test[features])
  35. # 获取乘客 ID
  36. ids = test['PassengerId'].values
  37. # 创建 csv
  38. submission_file = open("submission.csv", "w")
  39. # 写入这个 csv
  40. open_file_object = csv.writer(submission_file)
  41. # 写入 CSV 标题
  42. open_file_object.writerow(["PassengerId","Survived"])
  43. # 写入 CSV 的行
  44. open_file_object.writerows(zip(ids, predictions))
  45. # 关闭文件
  46. submission_file.close()

可视化决策树

  1. # 加载库
  2. from sklearn.tree import DecisionTreeClassifier
  3. from sklearn import datasets
  4. from IPython.display import Image
  5. from sklearn import tree
  6. import pydotplus
  7. # 加载数据
  8. iris = datasets.load_iris()
  9. X = iris.data
  10. y = iris.target
  11. # 创建决策树分类器对象
  12. clf = DecisionTreeClassifier(random_state=0)
  13. # 训练模型
  14. model = clf.fit(X, y)
  15. # 创建 DOT 数据
  16. dot_data = tree.export_graphviz(clf, out_file=None,
  17. feature_names=iris.feature_names,
  18. class_names=iris.target_names)
  19. # 绘制图形
  20. graph = pydotplus.graph_from_dot_data(dot_data)
  21. # 展示图形
  22. Image(graph.create_png())

png

  1. # 创建 PDF
  2. graph.write_pdf("iris.pdf")
  3. # 创建 PNG
  4. graph.write_png("iris.png")
  5. # True