机器学习算法库——scikit-learn基础
·
- 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 神经网络
更多推荐


所有评论(0)