• scikit-learn 库是当今最流行的机器学习算法库之一
    可用来解决分类与回归问题
  • 本文以鸢尾花数据集为例,简单了解八大传统机器学习分类算法的sk-learn实现
  • 欲深入了解传统机器算法的原理和公式推导,可以学习《统计学习方法》或《西瓜书》

第一部分 数据预处理

1.1 下载数据集

import seaborn as sns

iris = sns.load_dataset("iris")
# 如果下载不了,可以去https://github.com/mwaskom/seaborn-data下载后放到本地
# 之后用planets = pd.read_csv("iris.csv")加载
# 还可以用from sklearn import datasets
# sklearn_dataset = datasets.load_iris()
# iris = pd.DataFrame(sklearn_dataset.data, columns=sklearn_dataset.feature_names)

1.2 数据集的查看

print(type(iris))
<class 'pandas.core.frame.DataFrame'>
print(iris.shape)
(150, 5)
print(iris.head())
   sepal_length  sepal_width  petal_length  petal_width species
0           5.1          3.5           1.4          0.2  setosa
1           4.9          3.0           1.4          0.2  setosa
2           4.7          3.2           1.3          0.2  setosa
3           4.6          3.1           1.5          0.2  setosa
4           5.0          3.6           1.4          0.2  setosa
  • 前四列是特征,最后一列是标签
print(iris.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
sepal_length    150 non-null float64
sepal_width     150 non-null float64
petal_length    150 non-null float64
petal_width     150 non-null float64
species         150 non-null object
dtypes: float64(4), object(1)
memory usage: 6.0+ KB
None
  • 可以看出数据很干净,没有缺失,后面不用处理缺失了
print(iris.describe())
       sepal_length  sepal_width  petal_length  petal_width
count    150.000000   150.000000    150.000000   150.000000
mean       5.843333     3.057333      3.758000     1.199333
std        0.828066     0.435866      1.765298     0.762238
min        4.300000     2.000000      1.000000     0.100000
25%        5.100000     2.800000      1.600000     0.300000
50%        5.800000     3.000000      4.350000     1.300000
75%        6.400000     3.300000      5.100000     1.800000
max        7.900000     4.400000      6.900000     2.500000
print(iris.species.value_counts())
setosa        50
virginica     50
versicolor    50
Name: species, dtype: int64
  • 可以看出一共有三类鸢尾花,每类50个
import matplotlib.pyplot as plt

sns.pairplot(data=iris, hue="species")
plt.show()

在这里插入图片描述

  • 对角线上是对应维度下三种鸢尾花的边缘概率分布,分得比较开的说明数据比较容易分离
  • 可以看出花瓣长度与花瓣宽度的线性关系很明显,两者的边缘分布可以看出,它们的分类效果很好
  • 花萼长度与花萼宽度线性很差,边缘分布来看,分类效果也很糟糕
import pandas_profiling as ppf
ppf.ProfileReport(iris)

在这里插入图片描述

1.3 数据清洗(选择特征,处理缺失值等)

  • 考虑删除花萼的长度和宽度,只用花瓣的长度和宽度对鸢尾花进行分类
  • 这么做只是为了简化问题,实际上可能加上花萼的长度和宽度数据后分类效果更好
iris_simple = iris.drop(["sepal_length", "sepal_width"], axis=1)
print(iris_simple.head())
   petal_length  petal_width species
0           1.4          0.2  setosa
1           1.4          0.2  setosa
2           1.3          0.2  setosa
3           1.5          0.2  setosa
4           1.4          0.2  setosa

1.4 标签编码

  • 可以看到标签值都是字符串类型,但是有些算法在训练过程中用到的标签值必须是数值类型,所以需要对标签进行编码,把这三类分别映射成0,1,2
  • 标签编码除了本文中使用的LabelEncoder,还有Onehot
from sklearn.preprocessing import LabelEncoder
​
encoder = LabelEncoder()
iris_simple["species"] = encoder.fit_transform(iris_simple["species"])

print(iris_simple.head())
   petal_length  petal_width  species
0           1.4          0.2        0
1           1.4          0.2        0
2           1.3          0.2        0
3           1.5          0.2        0
4           1.4          0.2        0

1.5 数据集的标准化

  • 有的时候,不同特征之间,数值的绝对值差异比较大,比如说,有一列都是数千量级的,另一列都是0.1量级的。
  • 在有些算法里面,数据绝对值比较大,可能对算法的影响会更大,可能会把绝对值小的数据对算法的影响掩盖掉。
  • 此外,当不同特征的数据绝对值相差比较大的时候,会影响算法收敛速度。
  • 这种情况下,就需要对数据进行标准化,例如构造标准正态分布。
  • 本数据集特征比较接近,实际处理过程中未标准化
  • 除了示例中的StandardScaler,还有MinmaxScaler
from sklearn.preprocessing import StandardScaler
import pandas as pd

trans = StandardScaler()
_iris_simple = trans.fit_transform(iris_simple[["petal_length", "petal_width"]])
_iris_simple = pd.DataFrame(_iris_simple, columns = ["petal_length", "petal_width"])
print(_iris_simple.describe())
       petal_length   petal_width
count  1.500000e+02  1.500000e+02
mean  -8.652338e-16 -4.662937e-16
std    1.003350e+00  1.003350e+00
min   -1.567576e+00 -1.447076e+00
25%   -1.226552e+00 -1.183812e+00
50%    3.364776e-01  1.325097e-01
75%    7.627583e-01  7.906707e-01
max    1.785832e+00  1.712096e+00

1.6 构建训练集和测试集(本文暂不考虑验证集)

  • 回归或者分类算法,一般要将数据集分为三部分。
  • 训练集用来训练算法,得到收敛的模型。
  • 验证集用来验证训练出来的模型是不是足够优秀,通过不断调整模型,获得在验证集上表现好的模型。
  • 在经过多次训练和验证后,获得了我们认为的最好的模型,最后把它用在测试集上,看它的泛化能力是否足够好。
  • 为了简化,本文不考虑验证集。
from sklearn.model_selection import train_test_split
​
train_set, test_set = train_test_split(iris_simple, test_size=0.2)    # test_size 测试集百分比
print(test_set.head())
     petal_length  petal_width  species
3             1.5          0.2        0
111           5.3          1.9        2
24            1.9          0.2        0
5             1.7          0.4        0
92            4.0          1.2        1
iris_x_train = train_set[["petal_length", "petal_width"]]    # 剥离出特征
print(iris_x_train.head())
     petal_length  petal_width
63            4.7          1.4
93            3.3          1.0
34            1.5          0.2
35            1.2          0.2
126           4.8          1.8
iris_y_train = train_set["species"].copy()    # 剥离出标签
print(iris_y_train.head())
#上面不用加copy是因为构建了新的dataframe对象,此处获得的是Series视图,必须加copy,或者改成train_set[["species"]]
63     1
93     1
34     0
35     0
126    2
Name: species, dtype: int32
# 测试集也要剥离
iris_x_test = test_set[["petal_length", "petal_width"]]
iris_y_test = test_set["species"].copy()

第二部分 五大基本数据分类算法

2.1 k近邻算法

2.1.1 基本思想

  • 近邻:与待预测点最近的训练数据集中的k个邻居
  • 把k个近邻中出现次数最多的类别预测为待预测点的类别

2.1.2 sklearn实现

from sklearn.neighbors import KNeighborsClassifier
  • 构建分类器对象
clf = KNeighborsClassifier()
print(clf)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
                     metric_params=None, n_jobs=None, n_neighbors=5, p=2,
                     weights='uniform')
  • n_neighbors相当于k,这些参数都是可以自己调整以获得最优模型的。
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 翻转
print(encoder.inverse_transform(res))
['setosa', 'virginica', 'setosa', 'setosa', 'versicolor',
 'versicolor', 'setosa', 'virginica', 'versicolor', 'virginica',
 'versicolor', 'virginica', 'virginica', 'virginica', 'versicolor',
 'setosa', 'setosa', 'setosa', 'versicolor', 'setosa', 'virginica',
 'setosa', 'virginica', 'versicolor', 'setosa', 'versicolor',
 'setosa', 'setosa', 'versicolor', 'versicolor']
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%
  • 存储数据
out = iris_x_test.copy()
out["y"] = iris_y_test
out["pre"] = res
print(out.head())
out.to_csv("iris_predict.csv")
     petal_length  petal_width	y	pre
3             1.5          0.2  0	  0
111           5.3          1.9  2	  2  
24            1.9          0.2  0	  0
5             1.7          0.4  0	  0
92            4.0          1.2  1	  1

2.1.3 可视化

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
​
def draw(clf):    # 参数是训练的模型
​
    # 网格化
    M, N = 500, 500
    x1_min, x2_min = iris_simple[["petal_length", "petal_width"]].min(axis=0)
    x1_max, x2_max = iris_simple[["petal_length", "petal_width"]].max(axis=0)
    t1 = np.linspace(x1_min, x1_max, M)
    t2 = np.linspace(x2_min, x2_max, N)
    x1, x2 = np.meshgrid(t1, t2)
    
    # 预测
    x_show = np.stack((x1.flat, x2.flat), axis=1)
    y_predict = clf.predict(x_show)
    
    # 配色
    cm_light = mpl.colors.ListedColormap(["#A0FFA0", "#FFA0A0", "#A0A0FF"])
    cm_dark = mpl.colors.ListedColormap(["g", "r", "b"])
    
    # 绘制预测区域图
    plt.figure(figsize=(10, 6))
    plt.pcolormesh(t1, t2, y_predict.reshape(x1.shape), cmap=cm_light)
    
    # 绘制原始数据点
    plt.scatter(iris_simple["petal_length"], iris_simple["petal_width"], label=None,
                c=iris_simple["species"], cmap=cm_dark, marker='o', edgecolors='k')
    plt.xlabel("petal_length")
    plt.ylabel("petal_width")
    
    # 绘制图例
    color = ["g", "r", "b"]
    species = ["setosa", "virginica", "versicolor"]
    for i in range(3):
        plt.scatter([], [], c=color[i], s=40, label=species[i])    # 利用空点绘制图例
    plt.legend(loc="best")
    plt.title('iris_classfier')
    plt.show()
draw(clf)

在这里插入图片描述

  • 预测错误的点,可以明显看出,它们的5个近邻中,其它分类的颜色的比较多。

2.2 朴素贝叶斯算法

2.2.1 基本思想

  • 后验概率最大化,即,当X=(x1, x2)发生的时候,哪一个yk发生的概率最大

2.2.2 sklearn实现

  • 因为两个特征值都是连续的变量,所以用高斯朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
  • 构建分类器对象
clf = GaussianNB()
print(clf)
GaussianNB(priors=None, var_smoothing=1e-09)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)

[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]

  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

2.2.3 可视化

draw(clf)

在这里插入图片描述

2.3 决策树算法

2.3.1 基本思想

  • 决策树最常见的CART算法:每次通过一个特征,将数据尽可能的分为纯净的两类,递归的分下去。
  • 理论上,可以把数据完全分开,但是如果真的完全分开,极有可能就是过拟合,也就是说,泛化能力变差,再用新的数据进行预测,错误率会很高,所以一般会进行剪枝,不让它预测得太过。

2.3.2 sklearn实现

from sklearn.tree import DecisionTreeClassifier
  • 构建分类器对象
clf = DecisionTreeClassifier()
print(clf)
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
                       max_features=None, max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, presort=False,
                       random_state=None, splitter='best')
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

2.3.3 可视化

draw(clf)

在这里插入图片描述

2.4 逻辑回归算法

2.4.1 基本思想

  • 训练:通过一个映射方式,将特征X=(x1, x2) 映射成概率 P(y=ck), 求使得所有概率之积最大化的映射方式里的参数
  • 预测:计算P(y=ck) ,取概率最大的那个类别作为预测对象的分类

2.4.2 sklearn实现

from sklearn.linear_model import LogisticRegression
  • 构建分类器对象
    默认参数训练效果不是很好,所以需要调整。
    solver 求解器,默认’warn’
    max_iter 最大迭代次数,默认100。
clf = LogisticRegression(solver='saga', max_iter=1000)
print(clf)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=1000,
                   multi_class='warn', n_jobs=None, penalty='l2',
                   random_state=None, solver='saga', tol=0.0001, verbose=0,
                   warm_start=False)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

2.4.3 可视化

draw(clf)

在这里插入图片描述

2.5 支持向量机算法

2.5.1 基本思想

  • 以二分类为例,假设数据可用超平面完全分开
  • 这样的超平面有很多,要找到一个超平面,距离超平面最近的点到该平面的距离最大化。

2.5.2 sklearn实现

from sklearn.svm import SVC
  • 构建分类器对象
clf = SVC()
print(clf)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
    decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
    kernel='rbf', max_iter=-1, probability=False, random_state=None,
    shrinking=True, tol=0.001, verbose=False)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

2.5.3 可视化

draw(clf)

在这里插入图片描述

第三部分 三大集成方法

  • 以上是五种基本数据分类算法,一系列弱分类器组合起来,会组合成一个更强的分类器。

3.1 随机森林

3.1.1 基本思想

  • 训练集m,有放回的随机抽取m个数据,构成一组,共抽取n组采样集
  • n组采样集分别训练得到n个弱分类器
    弱分类器一般用决策树或神经网络
  • 将n个弱分类器进行组合得到强分类器
    组合方法,最简单的就是投票,n个分类器获得的结果进行投票,看看哪个类别被预测的最多。

3.1.2 sklearn实现

from sklearn.ensemble import RandomForestClassifier
  • 构建分类器对象
clf = RandomForestClassifier()
print(clf)
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
                       max_depth=None, max_features='auto', max_leaf_nodes=None,
                       min_impurity_decrease=0.0, min_impurity_split=None,
                       min_samples_leaf=1, min_samples_split=2,
                       min_weight_fraction_leaf=0.0, n_estimators='warn',
                       n_jobs=None, oob_score=False, random_state=None,
                       verbose=0, warm_start=False)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

3.1.3 可视化

draw(clf)

在这里插入图片描述

3.2 Adaboost

3.2.1 基本思想

  • 训练集m,给每个数据分配一个权重,用初始数据权重训练得到第一个弱分类器,根据误差率计算弱分类器系数,更新数据的权重
  • 使用新的权重训练得到第二个弱分类器,以此类推
  • 根据各自系数,将所有弱分类器加权求和获得强分类器

3.2.2 sklearn实现

from sklearn.ensemble import AdaBoostClassifier
  • 构建分类器对象
clf = AdaBoostClassifier()
print(clf)
AdaBoostClassifier(algorithm='SAMME.R', base_estimator=None, learning_rate=1.0,
                   n_estimators=50, random_state=None)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

3.2.3 可视化

draw(clf)

在这里插入图片描述

3.3 梯度提升树GBDT

3.3.1 基本思想

  • 训练集m,获得第一个弱分类器,获得真实值与预测值之间的残差,然后不断地拟合残差
  • 所有弱分类器相加得到强分类器

3.3.2 sklearn实现

from sklearn.ensemble import GradientBoostingClassifier
  • 构建分类器对象
clf = GradientBoostingClassifier()
print(clf)
GradientBoostingClassifier(criterion='friedman_mse', init=None,
                           learning_rate=0.1, loss='deviance', max_depth=3,
                           max_features=None, max_leaf_nodes=None,
                           min_impurity_decrease=0.0, min_impurity_split=None,
                           min_samples_leaf=1, min_samples_split=2,
                           min_weight_fraction_leaf=0.0, n_estimators=100,
                           n_iter_no_change=None, presort='auto',
                           random_state=None, subsample=1.0, tol=0.0001,
                           validation_fraction=0.1, verbose=0,
                           warm_start=False)
  • 训练
clf.fit(iris_x_train, iris_y_train)
  • 预测
res = clf.predict(iris_x_test)
print(res)
print(iris_y_test.values)
[0 2 0 0 1 1 0 2 1 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
[0 2 0 0 1 1 0 2 2 2 1 2 2 2 1 0 0 0 1 0 2 0 2 1 0 1 0 0 1 1]
  • 评估
accuracy = clf.score(iris_x_test, iris_y_test)
print("预测正确率:{:.0%}".format(accuracy))
预测正确率:97%

3.3.3 可视化

draw(clf)

第四部分 大杀器

  • 前面都是基础的算法,在处理小数据集的时候用一下也是可以的。
  • 实际上在比赛或者工作中,它们出现的频率不是那么高,现在比较流行的是以下算法。

4.1 xgboost

  • GBDT的损失函数只对误差部分做负梯度(一阶泰勒)展开
  • XGBoost损失函数对误差部分做二阶泰勒展开,更加准确,更快收敛

4.2 lightgbm

  • 微软开发,快速的,分布式的,高性能的基于决策树算法的梯度提升框架
  • 速度更快

4.3 stacking

  • 堆叠,或者叫模型融合
  • 先建立几个简单的模型进行训练,第二级学习器会基于前级模型的预测结果进行再训练

4.4 神经网络

更多推荐