此篇文章需要一些线性代数、矩阵分块和Numpy的基础,在文中对这些基础不再赘述

一.鸢尾花数据

在机器学习中,大部分数据均是矩阵类型的:我们先看一下鸢尾花数据:
在这里插入图片描述

鸢尾花有四个属性:花瓣长度、宽度、花萼长度、花萼宽度,每一组属性成为一个样本,属性称为样本的特征,四个属性确定了鸢尾花的类别,也称为标签,由此形成了数据集{(x, d)}。此数据可以用于分析鸢尾花的类别。
对于非数字的数据,我们要将他们映射为数字。如果类别数量较多,比如0,1,2等整形数字可以映射为 0->[1.0,0.0,0.0],1->[0.0,1.0,0.0],称为OneHot(独热编码)。

1.1 鸢尾花数据的获取

import sklearn.datasets as datasets

# 获得鸢尾花数据
X, d = datasets.load_iris(return_X_y=True)
# 打印样本数据
print(X)
# 打印样本信息
print(X.shape)
# 打印标签
print(d)

所得数据如下:

样本数据:
[[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 [4.6 3.1 1.5 0.2]
 .................
 [5.  3.6 1.4 0.2]]

数据排列. 150行,4列,每一行为一个样本,某一列代表所有矩阵的某一个属性
(150, 4)

标签数据:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]

1.2 保存到npz文件

npz为Numpy专用的二进制格式,可以将多个数组保存到一个文件中。

import sklearn.datasets as datasets 
import numpy as np 


X, d = datasets.load_iris(return_X_y=True)
# 数据保存到 npz文件中, 样本取名data, 标签为 target
np.savez("iris.npz", data=X, target=d)

1.3 npz文件的读取

import numpy as np

# 读取npz数据
iris_file = np.load("iris.npz")

X = iris_file["data"]
d = iris_file["target"]
print(X.shape, d.shape, X.dtype, d.dtype)

二.分析鸢尾花数据

2.1 先分析下鸢尾花的花瓣长度和宽度的关系

以花瓣长度为横坐标, 宽度为纵坐标, 属性 d区分鸢尾花不同的种类

"""
观察鸢尾花花瓣长度和宽度的关系
"""
import numpy as np
import matplotlib.pyplot as plt

plt.switch_backend("TkAgg")

x = np.load("iris.npz")["data"]
d = np.load("iris.npz")["target"]

# 分别取出花瓣长度和宽度的属性值
x1 = x[:, 0]
x2 = x[:, 1]

# 以花瓣长度为横坐标, 宽度为纵坐标, 属性 d区分鸢尾花不同的种类
plt.scatter(x1, x2, c=d)
plt.show()

在这里插入图片描述

我们观察图片可以看到, 左上角的一类鸢尾花已经通过花瓣长度和宽度被区分出来了,但是右下角的两类则掺和到了一起,但是这时我们不知道被区分出的是哪一类鸢尾花,我们改变下程序:

"""
观察鸢尾花花瓣长度和宽度的关系, 增加图例以区分不同种类
"""
import numpy as np
import matplotlib.pyplot as plt

plt.switch_backend("TkAgg")

x = np.load("iris.npz")["data"]
d = np.load("iris.npz")["target"]


# 想查看鸢尾花花瓣长度和宽度的关系
x1 = x[:, 0]
x2 = x[:, 1]

# 为不同种类的鸢尾花赋予红色, 绿色和蓝色
colors = ["#ff0000", "#00ff00", "#0000ff"]
for i in range(3):
    plt.scatter(x1[d == i], x2[d == i], color=colors[i], label=f"{i}")

# 增加图例
plt.legend()
plt.show()

在这里插入图片描述

我们可以看到, 鸢尾花第0种类型已经被区分出来了,而第一种和第二种则掺和在了一起

2.2 分析下鸢尾花的花萼长度和宽度的关系

在2.1中,我们通过花萼长度和宽度无法完全区分三种鸢尾花的类型,那么我们通过花萼长度和宽度进行一下分类:

"""
6.观察鸢尾花花萼长度和宽度的关系, 增加图例以区分不同种类
"""
import numpy as np
import matplotlib.pyplot as plt

plt.switch_backend("TkAgg")

x = np.load("iris.npz")["data"]
d = np.load("iris.npz")["target"]


# 想查看鸢尾花花萼长度和宽度的关系
x1 = x[:, 2]
x2 = x[:, 3]

# 为不同种类的鸢尾花赋予红色, 绿色和蓝色
colors = ["#ff0000", "#00ff00", "#0000ff"]
for i in range(3):
    plt.scatter(x1[d == i], x2[d == i], color=colors[i], label=f"{i}")

# 增加图例
plt.legend()
plt.show()

在这里插入图片描述

可以看到,我们此时已经完全区分出了三种不同鸢尾花的类型,所以在机械学习中,我们只需要花萼长度和花萼宽度就能彻底区分出三种不同类型的鸢尾花,这是传统的观察法做机械学习的方式。

2.3 鸢尾花的花萼长度和宽度的线性关系

我们通过对2.2的数据进行观察得知,鸢尾花的花萼长度与宽度存在较为明显的线性关系,但是通过观察无法量化,我们可以计算下两者的相关系数:

"""
7.计算鸢尾花花萼长度和宽度的线性相关系数
"""
import numpy as np
import matplotlib.pyplot as plt

plt.switch_backend("TkAgg")

x = np.load("iris.npz")["data"]
d = np.load("iris.npz")["target"]


def rho(x1, x2):
    return np.mean((x1 - np.mean(x1)) * (x2 - np.mean(x2))) / np.std(x1) / np.std(x2)


# 想查看鸢尾花花瓣长度和宽度的关系
x1 = x[:, 2]
x2 = x[:, 3]

# 计算总的线性相关性
print(rho(x1, x2))

# 为不同种类的鸢尾花赋予红色, 绿色和蓝色
colors = ["#ff0000", "#00ff00", "#0000ff"]
for i in range(3):
    # 按不同类别分别计算线性相关性
    x11 = x1[d == i]
    x22 = x2[d == i]
    print(i, rho(x11, x22))
    plt.scatter(x1[d == i], x2[d == i], color=colors[i], label=f"{i}")

# 增加图例
plt.legend()
plt.show()

0.9628654314027962
0 0.33163004080411873
1 0.7866680885228169
2 0.3221082159003183

可以看到,整体上的线性相关性 0.96,这是个很大的值,但是每个种类的线性相关性则较弱

三.对鸢尾花数据进行线性回归训练

sklearn中提供的 LinearRegression 是基于最小二乘的线性回归分析, 属于最简单的线性回归
注: 由于线性回归预测到的是具体的值, 所有最后采用四舍五入的近似值代表种类

3.1 对全部特征进行线性回归

"""
鸢尾花数据分类, 利用全部特征
线性回归(一元线性回归, LinearRegression基于最小二乘法)
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# 第一步: 特征工程

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target

# 切分训练集和测试集, 将 30% 的数据作为测试集, 数据切分前, 默认打乱顺序
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)


# 第二步: 训练模型

# 进行线性回归训练
model = LinearRegression()
model.fit(X_train, y_train)

# 训练集预测分数
train_score = model.score(X_train, y_train)
print("训练集预测分数 %s" % train_score)


# 第三步: 预测模型
test_score = model.score(X_test, y_test)
print("测试集预测分数 %s" % test_score)

# 模型使用
correct_cnt = 0
for i, j in zip(X_test, y_test):
    predict_species = model.predict([i])[0]
    if j == round(predict_species):
        correct_cnt += 1
    print("真实: %s, 预测: %s, 四舍五入: %s" % (j, predict_species, round(predict_species)))

print("正确率: %s" % (correct_cnt / len(X_test)))

训练集预测分数 0.9224162704009742
测试集预测分数 0.9459464721087354
真实: 0, 预测: -0.09210029974063577, 四舍五入: 0
真实: 1, 预测: 1.3230754305700516, 四舍五入: 1
真实: 1, 预测: 1.4085623874146287, 四舍五入: 1
真实: 2, 预测: 2.2356966635028614, 四舍五入: 2
........
真实: 2, 预测: 2.0246631721465307, 四舍五入: 2
真实: 0, 预测: -0.08112746128935067, 四舍五入: 0
真实: 0, 预测: 0.038152601465326064, 四舍五入: 0
真实: 1, 预测: 1.1788170129817281, 四舍五入: 1
真实: 2, 预测: 1.5288647020065906, 四舍五入: 2
真实: 0, 预测: -0.03902766897966653, 四舍五入: 0
真实: 1, 预测: 1.518017487100872, 四舍五入: 2
正确率: 0.9777777777777777

3.2 利用特征中的鸢尾花花瓣长度和宽度

"""
鸢尾花数据分类, 利用部分特征预测
线性回归(一元线性回归, LinearRegression基于最小二乘法)
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# 第一步: 特征工程

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target

# 切分训练集和测试集, 将 30% 的数据作为测试集, 数据切分前, 默认打乱顺序
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# 我们只用特征中的鸢尾花花瓣长度和宽度
X_train = X_train[:, 0:2]
X_test = X_test[:, 0:2]

# 第二步: 训练模型

# 进行线性回归训练
model = LinearRegression()
model.fit(X_train, y_train)

# 训练集预测分数
train_score = model.score(X_train, y_train)
print("训练集预测分数 %s" % train_score)


# 第三步: 预测模型
test_score = model.score(X_test, y_test)
print("测试集预测分数 %s" % test_score)

# 模型使用
correct_cnt = 0
for i, j in zip(X_test, y_test):
    predict_species = model.predict([i])[0]
    if j == round(predict_species):
        correct_cnt += 1
    print("真实: %s, 预测: %s, 四舍五入: %s" % (j, predict_species, round(predict_species)))

print("正确率: %s" % (correct_cnt / len(X_test)))

训练集预测分数 0.7214291998454474
测试集预测分数 0.7224547175700466
真实: 2, 预测: 2.3678245116114827, 四舍五入: 2
真实: 1, 预测: 1.901441650245596, 四舍五入: 2
真实: 0, 预测: -0.08917214867960443, 四舍五入: 0
真实: 2, 预测: 1.9969500642829663, 四舍五入: 2
..............
真实: 1, 预测: 1.093013428810205, 四舍五入: 1
真实: 1, 预测: 0.9394744141721756, 四舍五入: 1
真实: 1, 预测: 1.0814817939066004, 四舍五入: 1
正确率: 0.8

可以看到准确率不是很高

3.3 利用特征中的鸢尾花花瓣长度和宽度

"""
鸢尾花数据分类, 利用部分特征预测
线性回归(一元线性回归, LinearRegression基于最小二乘法)
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

# 第一步: 特征工程

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target

# 切分训练集和测试集, 将 30% 的数据作为测试集, 数据切分前, 默认打乱顺序
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# 我们只用特征中的鸢尾花花瓣长度和宽度
# X_train = X_train[:, 0:2]
# X_test = X_test[:, 0:2]

# 我们只用特征中的鸢尾花花萼长度和宽度
X_train = X_train[:, 2:4]
X_test = X_test[:, 2:4]


# 第二步: 训练模型

# 进行线性回归训练
model = LinearRegression()
model.fit(X_train, y_train)

# 训练集预测分数
train_score = model.score(X_train, y_train)
print("训练集预测分数 %s" % train_score)


# 第三步: 预测模型
test_score = model.score(X_test, y_test)
print("测试集预测分数 %s" % test_score)

# 模型使用
correct_cnt = 0
for i, j in zip(X_test, y_test):
    predict_species = model.predict([i])[0]
    if j == round(predict_species):
        correct_cnt += 1
    print("真实: %s, 预测: %s, 四舍五入: %s" % (j, predict_species, round(predict_species)))

print("正确率: %s" % (correct_cnt / len(X_test)))

训练集预测分数 0.9053543503798129
测试集预测分数 0.9635350764736765
真实: 2, 预测: 1.6114439490355665, 四舍五入: 2
真实: 0, 预测: 0.06867017955909605, 四舍五入: 0
真实: 0, 预测: -0.01248543183571793, 四舍五入: 0
真实: 1, 预测: 1.0429460927843661, 四舍五入: 1
.......................
真实: 1, 预测: 1.1529982990014347, 四舍五入: 1
真实: 2, 预测: 1.9704971625090262, 四舍五入: 2
真实: 0, 预测: -0.08216412059913059, 四舍五入: 0
正确率: 1.0

可以看到准确率还是很高的

四.对鸢尾花数据进行KNN算法归类

由于回归算法是预测的具体数值, 而不是分类算法, 这里我们采用knn算法进行归类

"""
鸢尾花数据分类
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

# 第一步: 特征工程

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target

# 切分训练集和测试集, 将 30% 的数据作为测试集, 数据切分前, 默认打乱顺序
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)


# 第二步: 训练模型

# 我们先将 超参数 k 设为 5, 正常情况下, 需要对超参数进行调优
model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)

# 训练集预测分数
train_score = model.score(X_train, y_train)
print("训练集预测分数 %s" % train_score)


# 第三步: 预测模型
test_score = model.score(X_test, y_test)
print("测试集预测分数 %s" % test_score)

# 模型使用
for i, j in zip(X_test, y_test):
    print("真实: %s, 预测: %s" % (j, model.predict([i])[0]))
训练集预测分数 0.9523809523809523
测试集预测分数 1.0
真实: 0, 预测: 0
真实: 2, 预测: 2
真实: 0, 预测: 0
.............
真实: 1, 预测: 1
真实: 0, 预测: 0
真实: 2, 预测: 2
真实: 0, 预测: 0

对超参数k进行调优

"""
鸢尾花数据分类 (超参数调优)
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

# 第一步: 特征工程

# 加载iris数据集
iris = load_iris()
X = iris.data
y = iris.target

# 切分训练集和测试集, 将 30% 的数据作为测试集, 数据切分前, 默认打乱顺序
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)


# 第二步: 训练模型

# 进行超参数调优, 确定 k 为何值时, 模型预测最准确

for n in range(1, 20):
    # 进行模型训练
    model = KNeighborsClassifier(n_neighbors=n)
    model.fit(X_train, y_train)

    # 训练集预测分数
    train_score = model.score(X_train, y_train)
    test_score = model.score(X_test, y_test)
    print("训练集分数 %s, 测试集分数 %s" % (train_score, test_score))

训练集分数 1.0, 测试集分数 0.9555555555555556
训练集分数 0.9714285714285714, 测试集分数 0.9777777777777777
训练集分数 0.9619047619047619, 测试集分数 0.9555555555555556
训练集分数 0.9619047619047619, 测试集分数 0.9333333333333333
训练集分数 0.9714285714285714, 测试集分数 0.9555555555555556
训练集分数 0.9619047619047619, 测试集分数 0.9777777777777777
训练集分数 0.9619047619047619, 测试集分数 0.9777777777777777
训练集分数 0.9619047619047619, 测试集分数 0.9555555555555556
训练集分数 0.9619047619047619, 测试集分数 1.0
训练集分数 0.9619047619047619, 测试集分数 0.9777777777777777
训练集分数 0.9714285714285714, 测试集分数 1.0
训练集分数 0.9619047619047619, 测试集分数 0.9777777777777777
训练集分数 0.9809523809523809, 测试集分数 1.0
训练集分数 0.9619047619047619, 测试集分数 0.9111111111111111
训练集分数 0.9523809523809523, 测试集分数 0.9777777777777777
训练集分数 0.9523809523809523, 测试集分数 0.9777777777777777
训练集分数 0.9619047619047619, 测试集分数 0.9777777777777777
训练集分数 0.9523809523809523, 测试集分数 0.9333333333333333
训练集分数 0.9428571428571428, 测试集分数 0.9777777777777777

我们可以通过测试集分数选择最优的K值

更多推荐