1.模型算法选择路径图
Image('sklearn.png')
2.数据处理基础
# 读取数据 nrows 前一百行
df = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/telecom_churn.csv',nrows=100)
# pd.factorize() 获取字符数字化表示
df['International plan'] = pd.factorize(df['International plan'])[0]
df['Voice mail plan'] = pd.factorize(df['Voice mail plan'])[0]
df['Churn'] = df['Churn'].astype('int')
states = df['State']
y = df['Churn']
# 去掉一些列
df.drop(['State', 'Churn'], axis=1, inplace=True)
# 数据集划分
X_train, X_holdout, y_train, y_holdout = train_test_split(df.values, y, test_size=0.3,
random_state=17)
# 网格搜索 + 5折交叉验证
from sklearn.model_selection import GridSearchCV, cross_val_score
tree_params = {'max_depth': range(5, 7),
'max_features': range(16, 18)}
tree_grid = GridSearchCV(tree, tree_params, cv=5, n_jobs=-1, verbose=True)
tree_grid.fit(X_train, y_train)
#列出交叉验证得出的最佳参数和相应的训练集准确率均值。
tree_grid.best_params_
tree_grid.best_score_
accuracy_score(y_holdout, tree_grid.predict(X_holdout))
3.可视化基础
import matplotlib.pyplot as plt
f, axes = plt.subplots(1, 4, sharey=True, figsize=(16, 6))
for i in range(4):
axes[i].imshow(X[i, :].reshape([8, 8]), cmap='Greys')
plt.show()
4.评测指标(有监督)
1分类指标评价计算示例
## accuracy 准确率
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 1, 0, 1]
y_true = [0, 1, 1, 1]
print('ACC:',accuracy_score(y_true, y_pred))
ACC: 0.75
## Precision,Recall,F1-score
from sklearn import metrics
y_pred = [0, 1, 0, 0]
y_true = [0, 1, 0, 1]
print('Precision',metrics.precision_score(y_true, y_pred))
print('Recall',metrics.recall_score(y_true, y_pred))
print('F1-score:',metrics.f1_score(y_true, y_pred))
Precision 1.0
Recall 0.5
F1-score: 0.666666666667
## AUC
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
print('AUC socre:',roc_auc_score(y_true, y_scores))
AUC score : 0.75
2回归指标评价计算示例
平均绝对误差 平均绝对误差(Mean Absolute Error,MAE):平均绝对误差,其能更好地反映预测值与真实值误差的实际情况,其计算公式如下:
均方误差 均方误差(Mean Squared Error,MSE),均方误差,其计算公式为:
%5E2%0A#card=math&code=MSE%3D%5Cfrac%7B1%7D%7BN%7D%E2%88%91_%7Bi%3D1%7D%5E%7Bn%7D%28y_i%E2%88%92%5Chat%7By%7D_i%29%5E2%0A&id=aprJt)
R2(R-Square)的公式为: 残差平方和:%5E2#card=math&code=SS%7Bres%7D%3D%E2%88%91%28y_i%E2%88%92%5Chat%7By%7D_i%29%5E2&id=PYjFT) 总平均值:![](https://g.yuque.com/gr/latex?SS%7Btot%7D%3D%E2%88%91(yi%E2%88%92%5Cbar%7By%7D_i)%5E2#card=math&code=SS%7Btot%7D%3D%E2%88%91%28y_i%E2%88%92%5Cbar%7By%7D_i%29%5E2&id=xVvSc)
其中表示y的平均值 得到表达式为:
%5E2%7D%7B%E2%88%91(yi%E2%88%92%5Cbar%7By%7D)%5E2%7D%0A#card=math&code=R%5E2%3D1%E2%88%92%5Cfrac%7BSS%7Bres%7D%7D%7BSS_%7Btot%7D%7D%3D1%E2%88%92%5Cfrac%7B%E2%88%91%28y_i%E2%88%92%5Chat%7By%7D_i%29%5E2%7D%7B%E2%88%91%28y_i%E2%88%92%5Cbar%7By%7D%29%5E2%7D%0A&id=Y9UMa)
用于度量因变量的变异中可由自变量解释部分所占的比例,取值范围是 0~1,越接近1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用x的变化来解释y值变化的部分就越多,回归的拟合程度就越好。所以也称为拟合优度(Goodness of Fit)的统计量。
表示真实值,表示预测值,表示样本均值。得分越高拟合效果越好。
# coding=utf-8
import numpy as np
from sklearn import metrics
# MAPE需要自己实现
def mape(y_true, y_pred):
return np.mean(np.abs((y_pred - y_true) / y_true))
y_true = np.array([1.0, 5.0, 4.0, 3.0, 2.0, 5.0, -3.0])
y_pred = np.array([1.0, 4.5, 3.8, 3.2, 3.0, 4.8, -2.2])
# MSE
print('MSE:',metrics.mean_squared_error(y_true, y_pred))
# RMSE
print('RMSE:',np.sqrt(metrics.mean_squared_error(y_true, y_pred)))
# MAE
print('MAE:',metrics.mean_absolute_error(y_true, y_pred))
# MAPE
print('MAPE:',mape(y_true, y_pred))
MSE: 0.287142857143
RMSE: 0.535857123815
MAE: 0.414285714286
MAPE: 0.14619047619
## R2-score
from sklearn.metrics import r2_score
y_true = [3, -0.5, 2, 7]
y_pred = [2.5, 0.0, 2, 8]
print('R2-score:',r2_score(y_true, y_pred))
R2-score: 0.948608137045
5.评测指标(无监督)
聚类评价指标
(1)轮廓系数:%3D%5Cfrac%20%7Bb(i)-a(i)%7D%20%7Bmax%5Cleft%20%5C%7B%20a(i)%2Cb(i)%20%5Cright%20%5C%7D%7D#card=math&code=s%28i%29%3D%5Cfrac%20%7Bb%28i%29-a%28i%29%7D%20%7Bmax%5Cleft%20%5C%7B%20a%28i%29%2Cb%28i%29%20%5Cright%20%5C%7D%7D&id=ItwVa)
轮廓系数是聚类效果好坏的一种评价方式。最佳值为1,最差值为-1。接近0的值表示重叠的群集。负值通常表示样本已分配给错误的聚类,因为不同的聚类更为相似。
(2) 熵:%20%3D%20Entropy(p1%2C…p_n)%20%3D%20-%20%5Csum%7Bi%3D1%7D%5E%7Bn%7Dpilog_2(p_i)#card=math&code=Entropy%28S%29%20%3D%20Entropy%28p_1%2C…p_n%29%20%3D%20-%20%5Csum%7Bi%3D1%7D%5E%7Bn%7Dp_ilog_2%28p_i%29&id=RoZmN)
熵越小,数据越纯;熵越大,数据越混乱。
注:熵为0的时候,所有样本的目标属性取值相同。
(3)纯度: ,其中 #card=math&code=Pi%20%3D%20max%28P%7Bij%7D%29&id=qHiey)
6.决策树
分割质量标准(分类)
- 熵:%20%3D%20Entropy(p1%2C…p_n)%20%3D%20-%20%5Csum%7Bi%3D1%7D%5E%7Bn%7Dpilog_2(p_i)#card=math&code=Entropy%28S%29%20%3D%20Entropy%28p_1%2C…p_n%29%20%3D%20-%20%5Csum%7Bi%3D1%7D%5E%7Bn%7Dp_ilog_2%28p_i%29&id=WshNp)
- 基尼不确定性(Gini uncertainty):%5E2#card=math&code=G%20%3D%201%20-%20%5Csum%5Climits_k%20%28p_k%29%5E2&id=cpj5c)
- 错分率(Misclassification error): 几乎不用
二元分类问题的熵和基尼不确定性为:
%20%5Clog2%7B(1%20-%20p%7B%2B%7D)%7D%0A#card=math&code=S%20%3D%20-p%2B%20%5Clog_2%7Bp%2B%7D%20-p-%20%5Clog_2%7Bp-%7D%20%3D%20-p%2B%20%5Clog_2%7Bp%2B%7D%20-%281%20-%20p%7B%2B%7D%29%20%5Clog_2%7B%281%20-%20p%7B%2B%7D%29%7D%0A&id=thElh)
%5E2%20%3D%202p%2B(1-p%2B)%0A#card=math&code=G%20%3D%201%20-%20p%2B%5E2%20-%20p-%5E2%20%3D%201%20-%20p%2B%5E2%20-%20%281%20-%20p%2B%29%5E2%20%3D%202p%2B%281-p%2B%29%0A&id=PmJVq)
熵的图像和两倍的基尼不确定性图像非常接近。因此,在实践中,这两个指标的效果基本上是一样的。
sklearn.tree.DecisionTreeClassifier 类的主要参数为:
- max_depth 树的最大深度;
- max_features 搜索最佳分区时的最大特征数(特征很多时,设置这个参数很有必要,因为基于所有特征搜索分区会很「昂贵」);
- min_samples_leaf 叶节点的最少样本数。
from sklearn.tree import DecisionTreeClassifier
# max_depth参数限制决策树的深度
clf_tree = DecisionTreeClassifier(criterion='entropy', max_depth=3,
random_state=17)
# 训练决策树
clf_tree.fit(train_data, train_labels)
predicted = clf_tree.predict(val_data)
# 可视化树
from sklearn import tree
tree.plot_tree(clf_tree)
绘制所得决策树
dot_data = StringIO()
export_graphviz(tree_grid.best_estimator_, feature_names=df.columns,
out_file=dot_data, filled=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
Image(value=graph.create_png())
回归问题中的决策树
当对数值变量进行预测时,我们构造决策树的思路和分类问题时所用的思路是一样的,但衡量决策树好坏的质量标准改变了,现在它的质量标准如下:
%5E2%2C%20%0A#card=math&code=D%20%3D%20%5Cfrac%7B1%7D%7B%5Cell%7D%20%5Csum%5Climits%7Bi%20%3D1%7D%5E%7B%5Cell%7D%20%28y_i%20-%20%5Cfrac%7B1%7D%7B%5Cell%7D%20%5Csum%5Climits%7Bj%3D1%7D%5E%7B%5Cell%7D%20y_j%29%5E2%2C%20%0A&id=k7ESR)
其中, 是叶节点中的样本数, 是目标变量的值。简单来说,通过最小化方差,使每个叶子中的目标特征的值大致相等,以此来划分训练集的特征。
决策树使用分段的常数函数逼近数据
from sklearn.tree import DecisionTreeRegressor
n_train = 150
n_test = 1000
noise = 0.1
def f(x):
x = x.ravel()
return np.exp(-x ** 2) + 1.5 * np.exp(-(x - 2) ** 2)
def generate(n_samples, noise):
X = np.random.rand(n_samples) * 10 - 5
X = np.sort(X).ravel()
y = np.exp(-X ** 2) + 1.5 * np.exp(-(X - 2) ** 2) + \
np.random.normal(0.0, noise, n_samples)
X = X.reshape((n_samples, 1))
return X, y
X_train, y_train = generate(n_samples=n_train, noise=noise)
X_test, y_test = generate(n_samples=n_test, noise=noise)
reg_tree = DecisionTreeRegressor(max_depth=5, random_state=17)
reg_tree.fit(X_train, y_train)
reg_tree_pred = reg_tree.predict(X_test)
plt.figure(figsize=(10, 6))
plt.plot(X_test, f(X_test), "b")
plt.scatter(X_train, y_train, c="b", s=20)
plt.plot(X_test, reg_tree_pred, "g", lw=2)
plt.xlim([-5, 5])
plt.title("Decision tree regressor, MSE = %.2f" %
(np.sum((y_test - reg_tree_pred) ** 2) / n_test))
plt.show()
随机森林
from sklearn.ensemble import RandomForestClassifier
forest = RandomForestClassifier(n_estimators=100, n_jobs=-1,
random_state=17)
np.mean(cross_val_score(forest, X_train, y_train, cv=5))
forest_params = {'max_depth': range(8, 10),
'max_features': range(5, 7)}
#------------分割线-------------------------------
forest_grid = GridSearchCV(forest, forest_params,
cv=5, n_jobs=-1, verbose=True)
# 输出最优参数(必要时需要加print())
forest_grid.fit(X_train, y_train)
forest_grid.best_params_, forest_grid.best_score_
accuracy_score(y_holdout, forest_grid.predict(X_holdout))
7.最近邻方法
在最近邻方法中,为了对测试集中的每个样本进行分类,需要依次进行以下操作:
- 计算训练集中每个样本之间的距离。
- 从训练集中选取 k 个距离最近的样本。
- 测试样本的类别将是它 k 个最近邻中最常见的分类。
在回归问题中应用最近邻方法很简单,仅需将上述步骤做一个小小的改动:第三步不返回分类,而是返回一个数字,即目标变量在邻居中的均值或中位数。
这一方式的显著特点是它具有惰性:当需要对测试样本进行分类时,计算只在预测阶段进行。由于这种特点,最近邻方法事先并不基于训练样本创建模型,这与上文提到的决策树不同。决策树是基于训练集构建的,在预测阶段仅通过遍历决策树就可以实现快速地分类。
最近邻方法的实际应用
- 在某些案例中,k-NN 可以作为一个模型的base-line。
- 在 Kaggle 竞赛中,k-NN 常常用于构建元特征(即 k-NN 的预测结果作为其他模型的输入),或用于堆叠/混合。
- 最近邻方法还可以扩展到推荐系统等任务中。
- 在大型数据集上,常常使用逼近方法搜索最近邻。
k-NN 分类/回归的效果取决于一些参数:
- 邻居数 k。
- 样本之间的距离度量(常见的包括 Hamming,欧几里得,余弦和 Minkowski 距离)。注意,大部分距离要求数据在同一尺度下,例如「薪水」特征的数值在千级,「年龄」特征的数值却在百级,如果直接将他们丢进最近邻模型中,「年龄」特征就会受到比较大的影响。
- 邻居的权重(每个邻居可能贡献不同的权重,例如,样本越远,权重越低)。
scikit-learn 的 KNeighborsClassifier 类
sklearn.neighbors.KNeighborsClassifier
类的主要参数为:
- weights:可设为 uniform(所有权重相等),distance(权重和到测试样本的距离成反比),或任何其他用户自定义的函数。
- algorithm(可选):可设为 brute、ball_tree、KD_tree、auto。若设为 brute,通过训练集上的网格搜索来计算每个测试样本的最近邻;若设为 ball_tree 或 KD_tree,样本间的距离储存在树中,以加速寻找最近邻;若设为 auto,将基于训练集自动选择合适的寻找最近邻的方法。
- leaf_size(可选):若寻找最近邻的算法是 BallTree 或 KDTree,则切换为网格搜索所用的阈值。
- metric:可设为 minkowski、manhattan、euclidean、chebyshev 或其他。
使用交叉验证对 k-NN 的 k 值(即邻居数)进行调优。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
knn_pipe = Pipeline([('scaler', StandardScaler()),
('knn', KNeighborsClassifier(n_jobs=-1))])
knn_params = {'knn__n_neighbors': range(6, 8)}
knn_grid = GridSearchCV(knn_pipe, knn_params,
cv=5, n_jobs=-1,
verbose=True)
knn_grid.fit(X_train, y_train)
# 最优结果输出
knn_grid.best_params_,knn_grid.best_score_,knn_grid.best_params_
accuracy_score(y_holdout, knn_grid.predict(X_holdout))
对比:决策树和最近邻方法的优势和劣势
决策树
优势:
- 生成容易理解的分类规则,这一属性称为模型的可解释性。例如它生成的规则可能是「如果年龄不满 25 岁,并对摩托车感兴趣,那么就拒绝发放贷款」。
- 很容易可视化,即模型本身(树)和特定测试对象的预测(穿过树的路径)可以「被解释」。
- 训练和预测的速度快。
- 较少的参数数目。
- 支持数值和类别特征。
劣势:
- 决策树对输入数据中的噪声非常敏感,这削弱了模型的可解释性。
- 决策树构建的边界有其局限性:它由垂直于其中一个坐标轴的超平面组成,在实践中比其他方法的效果要差。
- 我们需要通过剪枝、设定叶节点的最小样本数、设定树的最大深度等方法避免过拟合。
- 不稳定性,数据的细微变动都会显著改变决策树。这一问题可通过决策树集成方法来处理(以后的实验会介绍)。
- 搜索最佳决策树是一个「NP 完全」(NP-Complete)问题。了解什么是 NP-Complete 请点击 这里。实践中使用的一些推断方法,比如基于最大信息增益进行贪婪搜索,并不能保证找到全局最优决策树。
- 倘若数据中出现缺失值,将难以创建决策树模型。Friedman 的 CART 算法中大约 50% 的代码是为了处理数据中的缺失值(现在 sklearn 实现了这一算法的改进版本)。
- 这一模型只能内插,不能外推(随机森林和树提升方法也是如此)。也就是说,倘若你预测的对象在训练集所设置的特征空间之外,那么决策树就只能做出常数预测。比如,在我们的黄球和蓝球的例子中,这意味着模型将对所有位于 >19 或 <0 的球做出同样的预测。
最近邻方法
优势:
- 实现简单。
- 研究很充分。
- 通常而言,在分类、回归、推荐问题中第一个值得尝试的方法就是最近邻方法。
- 通过选择恰当的衡量标准或核,它可以适应某一特定问题。
劣势:
- 和其他复合算法相比,这一方法速度较快。但是,现实生活中,用于分类的邻居数目通常较大(100-150),在这一情形下,k-NN 不如决策树快。
- 如果数据集有很多变量,很难找到合适的权重,也很难判定哪些特征对分类/回归不重要。
- 依赖于对象之间的距离度量,默认选项欧几里得距离常常是不合理的。你可以通过网格搜索参数得到良好的解,但在大型数据集上的耗时很长。
- 没有理论来指导我们如何选择邻居数,故而只能进行网格搜索(尽管基本上所有的模型,在对其超参数进行调整时都使用网格搜索的方法)。在邻居数较小的情形下,该方法对离散值很敏感,也就是说,有过拟合的倾向。
- 由于「维度的诅咒」,当数据集存在很多特征时它的表现不佳。