分类算法
整理自黑马机器学习教程
sklearn 转换器与预估器
转换器
在特征工程处理的步骤中有用到转换器,一般使用流程为:
- 实例化一个转换器
- 调用fit_transform()
实际上fit_transform()可分为两个步骤进行,这里以标准化为例: x , = x − E ( x ) σ \displaystyle x^, = \frac{x-E(x)}{\sigma} x,=σx−E(x)- fit:计算每一列的方差、均值
- transfer:根据fit得到的值,对该列的值进行转换
估计器
sklearn中,是一类实现了算法的api。
- 用于分类的估计器:
- sklearn.neighbors K-近邻
- sklearn.naive_bayes 贝叶斯
- sklearn.linear_model.LogisticRegression 逻辑回归
- sklearn.tree 决策树和随机森林
- 用于回归的估计器:
- sklearn.linear_model.LinearRegression 线性回归
- sklearn.linear_model.Ridge 岭回归
- 用于无监督学习的估计器:
- sklearn.cluster.KMeans 聚类
使用流程
- 实例化一个estimator类
- estimator.fit(x_train, y_train)->根据训练集的特征值和目标值,生成模型
- 模型评估
- 直接评估真实值和预测值
- 计算准确率:estimator.score(x_train, y_train)
KNN算法
K近邻算法:如果一个样本在特征空间中K个最相似(即特征空间中最邻近)的样本中的大多数属于一个类别,那么该样本也属于这个类别。
如何计算特征距离
介绍几种距离计算公式:
- 欧式距离: ( a 1 − b 1 ) 2 + ( a 2 − b 2 ) 2 + ( a 2 − b 2 ) 2 \sqrt{(a_1-b_1)^2+(a_2-b_2)^2+(a_2-b_2)^2} (a1−b1)2+(a2−b2)2+(a2−b2)2
- 曼哈顿距离: ∣ a 1 − b 1 ∣ + ∣ a 2 − b 2 ∣ + ∣ a 3 − b 3 ∣ |a_1-b_1| + |a_2-b_2| + |a_3-b_3| ∣a1−b1∣+∣a2−b2∣+∣a3−b3∣;
- 明可夫斯基距离: ( ∑ i = 1 n ∣ x i − y i ∣ p ) 1 p (\sum_{i=1}^n |x_i-y_i|^p)^{\frac{1}{p}} (∑i=1n∣xi−yi∣p)p1
可以发现欧式距离和曼哈顿距离都是明可夫斯基距离的特殊情况
如何处理数据
K近邻对K的取值较为敏感:
- 如果K值过小,则容易受异常点影响
- 如果K值过大,则容易受样本不均衡的影响
同时不同量纲的数据会让大量纲的数据影响更多。
综上:我们需要将数据提前标准化
api 以鸢尾花为例
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# 获取数据
iris = load_iris()
# 划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=23)
# 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
# 训练集和测试集做相同处理(很重要!)
x_test = transfer.transform(x_test)
# KNN算法预估器 建立模型
estimator = KNeighborsClassifier(n_neighbors=3)
estimator.fit(x_train, y_train)
# 模型评估
# 1 直接对比真实值和预估值
y_predict = estimator.predict(x_test)
print(y_predict == y_test)
# 计算准确率
score = estimator.score(x_test, y_test)
print(score)
结果会受到数据集划分的影响(随机数种子为23时,准确率为1)
小结
- 优点
- 简单,易于理解,容易实现,无需训练
- 缺点
- 懒惰算法,对测试样本分类时计算量大,内存开销大
- 结果受K值影响
- 使用场景
- 小数据场景
模型选择与调优
KNN算法中我们需要确定一个K值,模型选择与调优可以帮助我们寻找合适的K值
交叉验证
可以让模型更加准确
以4折交叉验证为例:将训练集分为四组,其中一组作为验证集,经过四次训练,每次都更换不同的验证集,取平均值作为最终结果
超参数搜索-网格搜索(Grid Search)
通常情况下,很多参数需要手动指定(例如KNN中的K值),这种参数被称为超参数。
我们可以将这些超参数的取值记录在网格里,然后对网格数据进行遍历,寻找最优。
api
from sklearn.model_selection import GridSearchCV
# KNN算法预估器 建立模型
estimator = KNeighborsClassifier(n_neighbors=3)
# 添加网格搜索交叉验证
param_dict = {
"n_neighbors":[1, 3, 5, 7, 9, 11]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=10)
# 查看最佳参数等
print("最佳参数:\n", estimator.best_params_)
print("最佳结果:\n", estimator.best_score_)
print("最佳估计器:\n", estimator.best_estimator_)
print("交叉验证结果:\n", estimator.cv_results_)
为什么最佳结果比准确率?
因为这两者分别是对训练集和测试机的评估
朴素贝叶斯算法
前提假设:特征与特征之间是相互独立的
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B) = \frac {P(B|A)P(A)}{P(B)} P(A∣B)=P(B)P(B∣A)P(A)
使用场景: 文本分类
api
from sklearn.naive_bayes import MultinomialNB
# 贝叶斯
estimator = MultinomialNB()
estimator.fit(x_train, y_train)
小结
- 优点:
- 分类效率稳定
- 对确实数据不敏感,常用于文本分类
- 分类准确度高,速度快
- 缺点:
- 样本属性独立性假设,如果特征相关性较强则效果不理想
决策树
分类原理类似程序中的if-else,关键为找到最高效的决策顺序。
如何找到最高效的决策顺序
主要涉及两点:
- 在众多输入特征中选择最适合分枝的特征
- 如何从分组特性中寻找一个阈值作为最佳分割点
为此有定义信息熵:用于度量随机变量的不确定性
随机变量的熵:
$ H(X) = - \sum_{i=1}^n p(X_i)log_2 p(X_i)$
针对数量为d的样本集D,有k个种类,每个种类队以ing的样本数量为 C k C_k Ck,则样本集的熵为:
$ H(D) = - \sum_{i=1}^k \frac{C_i}{d}log_2\frac{C_i}{d}$
依据信息熵,我们可以通过三种决策树算法进行分类,将在另外文章中分享。
api
from sklearn.tree import DecisionTreeClassifier, export_graphviz
# 决策树
estimator = DecisionTreeClassifier(criterion="entropy")
estimator.fit(x_train, y_train)
# 计算准确率
score = estimator.score(x_test, y_test)
print(score)
# 决策树可视化
export_graphviz(estimator, out_file="tree.dot", feature_names=iris.feature_names)
小结
- 优点
- 简单理解和解释,树可视化
- 缺点
- 不能创建数据更为复杂的树(过拟合)
- 改进
- 剪枝
- 随机森林
随机森林
随机森林是一个包含多个决策树的分类器,输出结果由所有类别的众数决定。
原理过程
随机体现在两个方面:
- 训练集随机:bootstrap抽样(随机有放回)
- 特征随机:从M个特征中随机抽取m个特征(M >> m可以达到降维的目的)
api
因为有几个超参数,所以我们可以添加网格搜索来寻找最佳结果
from sklearn.ensemble import RandomForestClassifier
estimator = RandomForestClassifier()
# 网格搜索
param_dict = {
"n_estimators": [120, 200, 300, 500, 800, 1200],"max_depth": [5, 8, 15, 25, 30]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
小结
- 当前所有算法中,具有极好的准确率
- 能够有效地运行在大数据集上,能够处理高纬度特征的输入样本,不需要降维(因为随机抽取样本即特征)
- 能够评估各个特征在分类问题上的重要性(也是因为对特征进行随机采样)