监督学习——使用逻辑回归对鸢尾花种类进行分类
机器学习中另一个有名的数据集叫做Iris(鸢尾花)数据集,Iris数据集包含了来自三种不同品种:山鸢尾,变色鸢尾和弗吉尼亚鸢尾总共150朵鸢尾花的测量数据。这些测量数据包括花瓣的长度和宽度、花萼的长度和宽度,所有测量数据的计量单位为厘米。
我们的目标是构建一个机器学习模型,从这些已知品种的鸢尾花测量数据中学习而对新鸢尾花进行品种分类。
载入数据集
引入所须的模块,同样通过sklearn
模块访问Iris数据集。
import numpy as np
import cv2
from sklearn import datasets
from sklearn import model_selection
from sklearn import metrics
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot') #设置画图风格
导入Iris数据集
iris = datasets.load_iris()
通过dir
函数查看对象内的所有的属性和方法名称
dir(iris) #['DESCR', 'data', 'feature_names', 'filename', 'target', 'target_names']
-
DESCR
: 获取数据描述 -
data
: 特征数据数组,<num_samples
xnum_features
>的二维numpy.ndarray数组 -
feature_names
: 特征名称 -
target
: 标签数组, <num_samples
x 1>的一维numpy.ndarray数组 -
target_names
: 目标标签名
iris.data.shape #(150, 4)
表示数据集一共包含150个数据点,每个数据点包含4个特征。
iris.feature_names #['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
查询这4个特征的名称,对应前面提到的花萼和花瓣的尺寸信息。
iris.target.shape #(150,)
每个数据点都有一个类别标签储存在target中。
np.unique(iris.target) #array([0, 1, 2])
查询类别标签,共有三个类别(0, 1, 2)。
简化为二分类问题
为简化问题,仅关注两个类别,转化为二分类问题。最简单的方式是忽略属于某个类别的所有数据点,例子通过选择那些不属于类别2的所有行来忽略类别标签2。
idx = iris.target != 2
data = iris.data[idx].astype(np.float32)
target = iris.target[idx].astype(np.float32)
检查数据
设置模型前,使用matplotlib
创建一个散点图来观察数据,其中每个数据点的颜色对应其类别标签。为简化绘图,仅使用头两个特征(iris.feature_names[0]
为花萼的长度,iris.feature_names[1]
为花萼的宽度)。从下图中可清晰看到类有一个很好的分离。
plt.figure(figsize=(10, 6))
plt.scatter(data[:, 0], data[:, 1], c=target, cmap=plt.cm.Paired, s=100)
plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])
把数据分为训练集和测试集
设test_size
参数为0.1,表示选择10%的数据用于测试。而设置随机状态random_state=42
来控制随机状态,当random_state取某一个值时,也就确定了一种规则。
X_train, X_test, y_train, y_test = model_selection.train_test_split(
data, target, test_size=0.1, random_state=42
)
这里将数据分成了90%的训练数据和10%的测试数据。
通过查看返回的参数,验证获得了90个训练数据点和10个测试数据点。
X_train.shape, y_train.shape #((90, 4), (90,))
X_test.shape, y_test.shape #((10, 4), (10,))
训练分类器
创建一个逻辑回归分类器与创建一个k-NN分类器的步骤基本上是一样的(监督学习——使用OpenCV实现k-NN):
lr = cv2.ml.LogisticRegression_create()
指定期望的训练方法,这里选择cv2.ml.LogisticRegression_MINI_BATCH
。
设定使用每一个数据点都更新一次模型。
lr.setTrainMethod(cv2.ml.LogisticRegression_MINI_BATCH)
lr.setMiniBatchSize(1)
指定算法在结束之前的迭代次数(100):
lr.setIterations(100)
调用对象的train
方法进行训练:
lr.train(X_train, cv2.ml.ROW_SAMPLE, y_train);
训练阶段的目标是找到一组可以最好地把特征值转化为输出标签的权重。
一个单独的数据点由它的四个特征
f
0
f
1
f
2
f
3
f_0f_1f_2f_3
f0f1f2f3组成,因此设4个权重,而
x
=
w
0
f
0
+
w
1
f
1
+
w
2
f
2
+
w
3
f
3
x=w_0f_0+w_1f_1+w_2f_2+w_3f_3
x=w0f0+w1f1+w2f2+w3f3,以及
y
^
=
σ
(
x
)
\hat y=\sigma(x)
y^=σ(x)。
此外,算法还需添加一个额外的权重用于设置补偿或偏差,因此
x
=
w
0
f
0
+
w
1
f
1
+
w
2
f
2
+
w
3
f
3
+
w
4
x=w_0f_0+w_1f_1+w_2f_2+w_3f_3+w_4
x=w0f0+w1f1+w2f2+w3f3+w4。
通过下方代码来检索这些权重。
lr.get_learnt_thetas() #array([[-0.04090133, -0.01910263, -0.16340333, 0.28743777, 0.11909772]], dtype=float32)
代码的输出即为 w 0 w 1 w 2 w 3 w 4 w_0w_1w_2w_3w_4 w0w1w2w3w4各自的值。
测试分类器
计算分类器在训练数据集上的准确率:
ret, y_pred = lr.predict(X_train)
metrics.accuracy_score(y_train, y_pred) #1.0
训练数据集上的准确率为1.0,这个结果仅表明模型可以完美的记住训练数据集,并不意味着模型能够正确分类一个新的未知的数据点,因此需要在测试数据集上检查:
ret, y_pred = lr.predict(X_test)
metrics.accuracy_score(y_test, y_pred) #1.0
测试数据集上的准确率也为1.0,可得知所构建的模型比较完美。
参考书籍:《机器学习:使用OpenCV和Python进行智能图像处理》
(获取完整代码,可关注“HappyWin数学建模”公众号)