简介

老师信息

老师:吴法春
学校:山大(10年毕业)
工作:
TCL c语言 单片机 2.5年 深圳
\to vetch C++开发 ARM平台 3年
\to 青岛 山科智汇 java平台端 Android 3年
\to 东软 java方向 python人工智能


学习安排

前置基础:python基础,python数据处理和可视化基础

五天

第一阶段(2天)
机器学习,深度学习,框架(tensorflow/pytorch)

第二阶段(2-2.5天)
项目实训(分组 3-4人)

第三阶段(0.5-1天)
答辩(ppt,代码演示,15分钟左右)介绍,项目演示,代码演示


成绩

平时成绩30%(考勤为主,有事请假)
项目成绩70%(项目内容为主,答辩为辅,不能来要提前说)


上课时间

上午:8-12点

下午:13-17点


上课方式

每节课都录屏发群里
课件发群里
笔记发群里
环境搭建也发群里


项目

分类任务(数据任选,模型任选)
回归任务(任选)
模式识别(数据任选)
其他项目

要求:
数据、算法、模型、训练(不能直接拿网上的结果)、效果(指标,可视化)

答辩:
PPT(团队介绍、项目介绍、项目说明、效果展示)
成果物(数据、源码、或者其他)
实训模板(没有要求,吉大的或者网上的)

提交:
以上三个,答辩完成以后,以小组为单位打包提交即可。


框架

以前:tensorflow
现在:pytorch
没讲,看发的资料


环境搭建

建议在自己电脑上搭建环境
环境:anaconda + pycharm
按照老师的给的文档安装

anaconda
带各种包:数据分析、机器学习等等的环境

pycharm
编辑器,社区版免费,破解版没必要(费劲)


机器学习

主演教四个算法演示机器学习的流程

1、概述

AI
1956年第一次提出AI的概念。算力等等限制,受到打击

实现核心
机器学习
\to 神经网络 \in 机器学习
\to 深度学习 \in 神经网络,RNN、CNN

数据
清洗,筛选
整理结果:数据矩阵的样子

算法
参数

模型

输入新数据,推测结果

数据 输入\xrightarrow{输入} 算法 新数据\xrightarrow{新数据} 模型 推测\xrightarrow{推测} 结果

算法重要还是数据重要?
曲线图(纵轴效果,横轴数据、算法)

分类、回归
回归:预测具体数值
分类:预测属于哪一类(KNN算法:判断病人的肿瘤属于良性还是恶性的)


1、KNN算法

1.1、简介

优点

  • 思想极度简单
  • 应用数学知识少(近乎为零)
  • 效果好(缺点?)
  • 可以解释机器学习算法使用过程中的很多细节问题
  • 更完整的刻画机器学习应用的流程

原理案例介绍

假设现在设计一个程序判断一个新的肿瘤病人是良性肿瘤还是恶性肿瘤。

先基于原有的肿瘤病人的发现时间和肿瘤大小(特征)对应的良性/恶性(值)建立了一张散点图,横坐标是肿瘤大小,纵坐标是发现时间,红色代表良性,蓝色代表恶性,现在要预测的病人的颜色为绿色。

  1. 首先需要取一个k值(这个k值的取法后面会介绍),然后找到距离要预测的病人的点(绿点)距离最近的k个点。

  2. 然后用第一步中取到的三个点进行投票,比如本例中投票结果就是蓝:红 = 3:0 ,3>0,所以判断这个新病人幻的事恶性肿瘤。

  3. 本质:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。


1.2、简单实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# encoding=utf-8
# 创建时间:2023-02-20 9:24
import numpy as np
import matplotlib.pyplot as plt
# 特征
raw_data_x = [[3.393533211,2.331273381], # 肿瘤信息: 大小、时间
[2.110073483,1.781539638],
[1.343808831,3.368360954],
[3.582294042,4.679179110],
[2.280362439,2.866990263],
[7.423436942,4.696522875],
[5.745051997,3.533989803],
[9.172168622,2.511101045],
[7.792783481,3.424088941],
[7.939820817,0.791637231]
]
# 所属类别
raw_data_y = [0,0,0,0,0,1,1,1,1,1] # 0/1 恶性的还是良性的

# 转成numpy数组
X_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)

# 要预测的点
x = np.array([8.093607318,3.365731514])

# 绘图
plt.scatter(X_train[y_train == 0,0],X_train[y_train == 0,1],color='g')
plt.scatter(X_train[y_train == 1,0],X_train[y_train == 1,1],color='r')
plt.scatter(x[0],x[1],color='b')
plt.show()

欧拉距离:计算超平面两个点的距离

KNN 实现过程简单编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# encoding=utf-8
# 创建时间:2023-02-20 9:35
import numpy as np
import matplotlib.pyplot as plt
# 特征
raw_data_x = [[3.393533211,2.331273381], # 肿瘤信息: 大小、时间
[2.110073483,1.781539638],
[1.343808831,3.368360954],
[3.582294042,4.679179110],
[2.280362439,2.866990263],
[7.423436942,4.696522875],
[5.745051997,3.533989803],
[9.172168622,2.511101045],
[7.792783481,3.424088941],
[7.939820817,0.791637231]
]
# 所属类别
raw_data_y = [0,0,0,0,0,1,1,1,1,1] # 0/1 恶性的还是良性的

# 转成numpy数组
X_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)

# 要预测的点
x = np.array([8.093607318,3.365731514])

# 绘图
# plt.scatter(X_train[y_train == 0,0],X_train[y_train == 0,1],color='g')
# plt.scatter(X_train[y_train == 1,0],X_train[y_train == 1,1],color='r')
# plt.scatter(x[0],x[1],color='b')
# plt.show()

# ==========================================================================
from math import sqrt
distances = [] # 存计算出来的距离
for x_train in X_train:
# 欧拉
# **2 求平方
d = sqrt(np.sum((x_train - x)**2))
distances.append(d)
# 生成表达式
# distances = [sqrt(np.sum((x_train - x)**2)) for x_train in X_train]
print('distances=')
print(distances)

# 返回排序后的结果的索引,也就是距离测试点距离最近的点的排序坐标数组
nearset = np.argsort(distances)
print('nearset=') # argsort()沿着指定的轴,对输入数组的元素值进行排序,并返回排序后的元素索引数组
print(nearset)

# 投票
k = 6
# print('投票结果=')
# print([1 if key >= k else 0 for key in nearset])
# 求出距离测试点最近的6个点的类别
topK_y = [y_train[i] for i in nearset[:k]]
print('topK_y=')
print(topK_y)

# collections的Counter方法可以求出一个数组的相同元素的个数,返回一个dict【key=元素名,value=元素个数】
from collections import Counter

# most_common方法求出最多的元素对应的那个键值对
votes = Counter(topK_y)
print('votes=')
print(votes)

mc1 = votes.most_common(1)
print('mc1=')
print(mc1)
# mc2 = votes.most_common(2)
# print('mc2=')
# print(mc2)

# 预测: 最多的元素对应的那个键值对的键
predict = mc1[0][0]
print('predict=')
print(predict)

1.3、机器学习套路

可以说KNN是一个不需要训练过程的算法 k近邻算法是非常特殊的,可以被认为是没有模型的算法。为了和其他算法统一,可以认为训练数据集就是模型


1.4、判断机器学习算法的性能

训练数据集,测试数据集
不能用训练数据集来测试,所以要划分数据集为训练数据集,测试数据集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# encoding=utf-8
# 创建时间:2023-02-20 10:55
# permutation(n) 给出从0到n-1的一个随机排列
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets # 导入数据集
iris = datasets.load_iris()
X = iris.data[:,:2] # 前两个特征
y = iris.target
"""
目的:随机 拆分出 训练集 测试集
"""
print('=========================================================')
shuffle_indexes = np.random.permutation(len(X))
print(shuffle_indexes)

# 测试数据集的比例
test_ratio = 0.2
# 获取测试数据集
test_size = int(len(X) * test_ratio)


test_indexes = shuffle_indexes[:test_size]
train_indexes = shuffle_indexes[test_size:]

print('=========================================================')
X_train = X[train_indexes]
y_train = y[train_indexes]
print(X_train)
print(y_train)

print('=========================================================')
X_test = X[test_indexes]
y_test = y[test_indexes]
print(X_test)
print(y_test)

print('=========================================================')
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)


1.5、加载鸢尾花数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# encoding=utf-8
# 创建时间:2023-02-20 10:38
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn import datasets # 导入数据集
# 代码下载150条,官网更多
iris = datasets.load_iris()
print(iris.DESCR) # 描述
print('===================================================================')
print(iris.data) # 数据
print(iris.data.shape)
print('===================================================================')
print(iris.feature_names) # 特征名称
print('===================================================================')
print(iris.target) # 标记信息
print(iris.target.shape)
print(iris.target_names) # 标记名称

# 绘图
X = iris.data[:,:2] # 前两个特征
# plt.scatter(X[:,0], X[:,1])
# plt.show()

y = iris.target
# plt.scatter(X[y == 0,0], X[y == 0,1], color="red")
# plt.scatter(X[y == 1,0], X[y == 1,1], color="blue")
# plt.scatter(X[y == 2,0], X[y == 2,1], color="green")
# plt.show()

# plt.scatter(X[y == 0,0], X[y == 0,1], color="red", marker="o")
# plt.scatter(X[y == 1,0], X[y == 1,1], color="blue", marker="+")
# plt.scatter(X[y == 2,0], X[y == 2,1], color="green", marker="x")
# plt.show()

X = iris.data[:,2:] # 后两个特征
plt.scatter(X[y == 0,0], X[y == 0,1], color="red", marker="o")
plt.scatter(X[y == 1,0], X[y == 1,1], color="blue", marker="+")
plt.scatter(X[y == 2,0], X[y == 2,1], color="green", marker="x")
plt.show()

1.6、手写字数据集

11-knn手写数字测试.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# encoding=utf-8
# 创建时间:2023-02-20 12:48
from sklearn import datasets

digits = datasets.load_digits()
print(digits.keys())
print(digits.DESCR)
print('==================================================')
X = digits.data
print(X.shape)
print(X[:10])
y = digits.target
print(y.shape)
print(y[:100])
print('==================================================')
some_digit = X[666]
some_digit_image = some_digit.reshape(8, 8)

import matplotlib
import matplotlib.pyplot as plt

plt.imshow(some_digit_image, cmap=matplotlib.cm.binary)
plt.show()

# =================================================================
from playML.module_selection import train_test_split
from playML.KNN import KNNClassifier
# MyKnn = __import__('04-MyKnn')

X_train, y_train, X_test, y_test = train_test_split(X, y, test_radio=0.2, seed=True)
# 训练
my_knn_clf = KNNClassifier(k=3)
# my_knn_clf = MyKnn.KNNClassifier(k=3)
# 预测
my_knn_clf.fit(X_train, y_train)
y_predict = my_knn_clf.predict(X_test)
print(y_predict)

# 准确率
print(sum(y_predict == y_test) / len(y_test))

1.7、超参数和模型参数

  • 超参数: 在算法运行前需要决定的参数
  • 模型参数: 算法过程中学习的参数

kNN算法没有模型参数
kNN算法中的k是典型的超参数

  • 寻找好的超参数
    • 领域知识
    • 经验数值
    • 实验搜索

寻找最好的k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# encoding=utf-8
# 创建时间:2023-02-20 20:00
# 思路,遍历1-11,分别拿每一个k去调用算法,得出分数,取得分最高的那个k
from sklearn import datasets

digits = datasets.load_digits()
X = digits.data
y = digits.target
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
from sklearn.neighbors import KNeighborsClassifier

best_score = 0.0
best_k = -1
for k in range(1, 11):
knn_clf = KNeighborsClassifier(n_neighbors=k)
knn_clf.fit(X_train, y_train)
score = knn_clf.score(X_test, y_test)
if score > best_score:
best_k = k
best_score = score

# 不管警告
print("best_k =", best_k)
print("best_score =", best_score)
  • kNN的另外一个超参数:距离的权重

一般情况下使用距离的导数作为权证

考虑距离:红色:1蓝色: 1/3+ 1/4 =7/12红色胜

考虑距离?不考虑距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# encoding=utf-8
# 创建时间:2023-02-20 20:00
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets

digits = datasets.load_digits()
X = digits.data
y = digits.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=666)
# =======================================================
best_method = ""
best_score = 0.0
best_k = -1
# 考虑距离?不考虑距离
for method in ["uniform","distance"]:
for k in range(1,11):
knn_clf = KNeighborsClassifier(n_neighbors=k,weights=method)
knn_clf.fit(X_train,y_train)
score = knn_clf.score(X_test,y_test)
if score > best_score:
best_k = k
best_score = score
best_method = method

# 不管警告
print("best_k=",best_k)
print("best_score=",best_score)
print("best_method=",best_method)

什么是距离?

  • 欧拉距离

i=1n(Xi(a)Xi(b))2\sqrt{\sum^n_{i=1}(X_i^{(a)}-X_i^{(b)})^2}

  • 曼哈顿距离

i=1nXi(a)Xi(b)\sum_{i=1}^n|X_i^{(a)}-X_i^{(b)}|

  • 两种距离的整理对比

(i=1nXi(a)Xi(b))11(\sum_{i=1}^n|X_i^{(a)}-X_i^{(b)}|)^{\frac{1}{1}}

(i=1nXi(a)Xi(b)2)12(\sum_{i=1}^n|X_i^{(a)}-X_i^{(b)}|^2)^{\frac{1}{2}}

(i=1nXi(a)Xi(b)p)1p(\sum_{i=1}^n|X_i^{(a)}-X_i^{(b)}|^p)^{\frac{1}{p}}

  • 明克夫斯基距离Minkowski Distance

(i=1nXi(a)Xi(b)p)1p(\sum_{i=1}^n|X_i^{(a)}-X_i^{(b)}|^p)^{\frac{1}{p}}

到这里,我们获得了一个新的超参数 p

搜索明可夫斯基距离相应的p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# encoding=utf-8
# 创建时间:2023-02-20 13:08
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets

digits = datasets.load_digits()
X = digits.data
y = digits.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=666)
# =======================================================
best_p = -1
best_score = 0.0
best_k = -1
for k in range(1,11):
for p in range(1,6):
knn_clf = KNeighborsClassifier(n_neighbors=k,weights='distance',p=p)
knn_clf.fit(X_train,y_train)
# 只有一个标准 score, 实际情况一定不止一个
score = knn_clf.score(X_test,y_test)
if score > best_score:
best_k = k
best_score = score
best_p = p

print("best_p=",best_p)
print("best_k=",best_k)
print("best_score=",best_score)

找最优参数


1.9、数据归一化处理

样本间的距离被一个字段所主导

解决方案 :将所有的数据映射到同一尺度

  • 最值归一化 normalization:把所有数据映射到 0-1 之间

适合数值分布比较均匀,有边界的数据集

xscale=xxminxmaxxminx_{scale}=\frac{x-x_{min}}{x_{max}-x_{min}}

  1. 将这个数据映射到0~Xmax-Xmin 之间
  2. 然后对于每个x相比于整个范围所占的比例

适用于分布有明显边界的情况;
outlier影响较大

  • 均值方差归一化 standardization(常用)

把所有数据归一到均值为0方差为1的分布中
适用于数据分布没有明显边界;有可能存在极端情况值

xscale=xxmeansx_{scale}=\frac{x-x_{mean}}{s}


1.10、对测试数据集如何归一化?

测试数据是模拟真实环境

  • 真实环境很有可能无法得到所有测试数据的均值和方差
  • 对数据的归一化也是算法的一部分

在scikit-learn中使用Scaler


1.11、KNN的缺点

最大的缺点:效率低下
如果训练集有m个样本,n个特征,则预测每一个新的数据,需要O(m*n)


2、线性回归算法

2.1、简介

  • 解决回归问题
  • 思想简单,实现容易
  • 许多强大的非线性模型的基础
  • 结果具有很好的可解释性
  • 蕴含机器学习中的很多重要思想

线性回归算法以一个坐标系里一个维度为结果,其他维度为特征(如二维平面坐标系中横轴为特征,纵轴为结果),无数的训练集放在坐标系中,发现他们是围绕着一条执行分布。线性回归算法的期望,就是寻找一条直线,最大程度的“拟合”样本特征和样本输出标记的关系

实现简单线性回归法

1
2
3
4
5
6
7
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1., 2., 3., 4., 5.])
y = np.array([1., 3., 2., 3., 5.])
plt.scatter(x, y)
plt.axis([0, 6, 0, 6])
plt.show()

3、梯度下降法

  • 不是一个机器学习算法
  • 是一种基于搜索的最优化方法
  • 作用:最小化一个损失函数
  • 梯度上升法:最大化一个效用函数

以下是定义了一个损失函数以后,参数theta对应的损失函数J的值对应的示例图,我们需要找到使得损失函数值J取得最小值对应的θ\theta(这里是二维平面,也就是我们的参数只有一个)

在直线方程中,导数代表斜率 在曲线方程中,导数代表切线斜率 导数代表θ\theta单位变化时,J相应的变化

η\eta称为学习率(learning rate);
η\eta的取值影响获得最优解的速度;
η\eta取值不合适,甚至得不到最优解;
η\eta是梯度下降法的一个超参数。

η\mathbf{\eta}取值的影响

其他注意事项

并不是所有函数都有唯一的极值点

解决方案:
多次运行,随机化初始点;
梯度下降法的初始点也是一个超参数。

线性回归法的损失函数i=1m(y(i)y^(i))2\sum_{i=1}^m(y^{(i)}-\hat{y}^{(i)})^2具有唯一的最优解

多元线性回归中的梯度下降法

套路

模型
数学推导(其他方法)损失函数或者效应函数

深度学习

1、感知机

2、神经网络