Python培训Week5

复习

预测模型

image.png

评估模型

对多个模型进行选择,基于准确率accuracy score进行。

image.png

其他

都是基于概率论的贝叶斯公式bayes‘ rule。

主干工作是前面的2个模型,后期的工作是研究各个算法(课堂只用了KNN等),拓宽广度为工作服务,但暂时先不必研究深度,后期如果研究透了再研究。

学者一般是只研究理论,而不实践应用。
我们的优势是可以接触生产环境、把理论应用到实践中,然后如果发现问题,如性能问题等,进行优化,就可以研究理论进行优化、发表论文。外国很多人也是这样做的。

在不疑处有疑。 在别人不怀疑的地方怀疑

本节预览Data preprosessing、Model Selection(对评估模型优化)

这节课程主要是这3部分,重点是2和3。

image.png

  1. Data preprosessing数据预处理,类似数据清洗。
    为什么需要Data preprosessing?
    比如直接使用评估模型时,发现结果accuracy score都是忽高忽低,不稳定,无法根据结果进行评估。

  2. 交叉评估模型Model Selection
    accuracy score只是入门,实际中使用的是交叉评估模型、Cross score。

  3. 如何根据客户数据对算法进行选择(这部分最耗时,也是实际工作中的主要内容;其他classification, regression, clustering里的具体算法都是工具箱的工具)。实际工作中算法主要是为了优化,根据算法本身手动实现的代码,而不是采用库中的标准教科书算法。

image.png

Preprocessing数据预处理和Dimensionality reduction降维处理比较类似。
但是前者是数据处理前,后者是完成后的优化。而且后者需要在不降低准确度的情况下降维,也要把握好度,更重要。后面的课程再讲

Preprosessing

因为算法对数据有要求,所以只针对数据部分x进行处理,不改变结果y(target)

  1. Rescale 缩放
    类似1/4 -> 2/8,不影响结果。
  2. Standardize 标准化
  3. Normalize 规范化
  4. Binarize 二进制化
    如识别手写数字,把彩色图片(每个像素介于[0,15])转换为[0,1]的字符串,有笔迹则为1,否则0。
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
import pandas as pd  
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import Normalizer
from sklearn.preprocessing import Binarizer

import numpy as np

data_set = pd.read_csv("pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label


#Rescale缩放
mms = MinMaxScaler()
X_rescaled = mms.fit_transform(X,y) # Fit to data, then transform it.

np.set_printoptions(precision=3) # X_rescaled原始数据难以阅读,格式化打印,不改变实际数据
print(X_rescaled) # 输出0-1的数字


# Standardize
ss = StandardScaler()
X_rescaled = ss.fit_transform(X,y)
print(X_rescaled)


# Normalize
nl = Normalizer()
X_rescaled = nl.fit_transform(X,y)
print(X_rescaled)


# Binarize
b = Binarizer()
X_rescaled = b.fit_transform(X) # 这里的数据并不适合Binarize, 只用于演示。
print(X_rescaled)

# 无论哪种方式,都会改变数据,但不会影响后续数据分析的结果
# 因此可以实现2个目的: 1.数据预处理 2.加密,隐藏年龄、单价等数据(但不影响结果)

实例1-Predict-lg算法

上一节课使用了决策树算法,判断糖尿病。这次尝试使用logistic regression算法。

python中如何判断算法属于哪种分类?
可以从python导入包的函数的后缀,如:
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
第一个是Regression,后2个是Classification

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression


data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

lr = LogisticRegression()
lr.fit(X,y)

直接使用会报错

STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
Increase the number of iterations (max_iter) or scale the data as shown in:
https://scikit-learn.org/stable/modules/preprocessing.html

2种方案:增加迭代次数或者scale缩放数据。
可以查看LogisticRegression类,向上翻看注释的具体解释,也可以查看、深入学习相关资料。


max_iter : int, default=100
Maximum number of iterations taken for the solvers to converge.

image.png

带团队时,一定要一开始定好规范,比如注释等,后面会很容易。

方案1:
不改数据,修改算法。修改为下面代码就可以

1
lr = LogisticRegression(max_iter=200)

方案2:
修改数据,不改算法。lr.fit之前先处理数据,并使用处理后的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler


data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

mms = MinMaxScaler() #修改这里1
X_rescaled = mms.fit_transform(X) #修改这里2

lr = LogisticRegression()
lr.fit(X_rescaled,y) #修改这里3

添加测试数据,进行预测。最终结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler


data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

mms = MinMaxScaler()
X_rescaled = mms.fit_transform(X)

lr = LogisticRegression()
lr.fit(X_rescaled,y)

test_data = [7, 196, 90, 0, 0, 39.8, 0.451, 41]
y_pred = lr.predict(np.array(test_data).reshape(1,-1)) #处理为1行多列的矩阵
print(y_pred)

输出:

[1]

表示患有糖尿病

实例2-Model Selection-lg算法

类似前面的,使用logistic regression算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

# split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25)

# fit
lr = LogisticRegression()
lr.fit(X_train.values,y_train.values)

y_pred = lr.predict(np.array(X_test))
print(accuracy_score(y_test,y_pred))

结果发现仍然有之前的报错:

STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.

Increase the number of iterations (max_iter) or scale the data as shown in:
https://scikit-learn.org/stable/modules/preprocessing.html

方案1:
不改数据,修改算法。修改为下面代码就可以

1
2
lr = LogisticRegression(max_iter=200)  
lr.fit(X_train.values,y_train.values)

输出结果

0.64

方案2:
修改数据,不改算法。lr.fit之前先处理数据,并使用处理后的数据。

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
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

# split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25)

# rescale
mms = MinMaxScaler()
X_train_rescaled = mms.fit_transform(X_train)

# fit
lr = LogisticRegression()
lr.fit(X_train_rescaled,y_train)

y_pred = lr.predict(np.array(X_test))
print(accuracy_score(y_test,y_pred))

输出结果

0.36

结论*

可以看出,2种方案结果差异很大。

实际上经常会发现,同样的数据,不同的算法会有不同的效果。数据和算法要匹配才能取得最佳效果。(这里的是医疗数据,KMeans算法最合适;上周的手写数字的数据在KNN算法下最优。)

其次,需要进行模型优化
image.png

  1. 取平均值思路
    多次计算,取均值,最后的结果称作cross value score

  2. 测试集质量思路
    测试集是随机选取的,它选取的质量影响结果好坏。
    K_fold方法,将数据集分为n份,循环n次,每次将第i个作为测试集,其余为训练集,进行计算得到score_i。最后共n个score,取平均值mean。具体n取多少取决于数据量

模型优化-KFold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd  
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score

# read data
data_set = pd.read_csv("../pima-indians-diabetes.csv")
feature_columns = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age']
X = data_set[feature_columns]
y = data_set.label

# rescale
mms = MinMaxScaler()
X_rescaled = mms.fit_transform(X)

# fit
kf = KFold(n_splits=10) # n_splits=5 by default
lr = LogisticRegression()
cv_results = cross_val_score(lr, X_rescaled, y, cv=kf)

print(cv_results)
print("mean: %.2f var: %.2f std: %.2f" % (cv_results.mean(), cv_results.var(), cv_results.std()) )

输出结果:

[0.6 0.4 0.6 0.6 0.8 0.8 0.7 0.8 0.8 0.7]
mean: 0.68 var: 0.02 std: 0.12

最后一行输出中,平均值为最终结果(越大越好),var和std是方差和标准差,用于评估准确率的稳定性(越小越好)

即使是这样,也可能不够好。比如取样的时候某一测试集结果值y都为1(其他数据都作为训练集),这样取值不均匀,不够好。
image.png

优化思路:

  1. 每次fold之前根据y值进行“洗牌”,将标签值打乱,确保fold后每组取值均匀。
  2. 每轮一次fold,多次重复计算,N-Repeated。
    最后如果够好了,可以直接存档,保存数据和其他信息,便于后期直接处理(不再需要预处理)。

Model Selection

使用同一组数据不同算法分别进行评估,最后根据结果选择出最适配的算法。

因为前面KFold算法只是随机选取,可能因为一组中label值不够均匀导致偏差较大,因此更换为增强版KFold算法StratifiedKFold。
下面使用鸢尾花数据对KNN、决策树、高斯NB和SVC算法进行比较。

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
from sklearn import datasets  

from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score

X,y = datasets.load_iris(return_X_y=True)

models = []
names = []
cv_results = []
models.append(("KNN", KNeighborsClassifier()))
models.append(("DTC", DecisionTreeClassifier()))
models.append(("GNB", GaussianNB()))
models.append(("SVM", SVC()))

for name, model in models:
skfold = StratifiedKFold(n_splits=10)
cv_score = cross_val_score(model, X, y, cv=skfold, scoring='accuracy')
cv_results.append(cv_score)
names.append(name)
print("%s: %f %.3f %.4f"% (name, cv_score.mean(), cv_score.std(), cv_score.var()))

输出如下:

1
2
3
4
KNN: 0.966667 0.045 0.0020  
DTC: 0.953333 0.043 0.0018
GNB: 0.953333 0.043 0.0018
SVM: 0.973333 0.033 0.0011

第一列为均值(看这个评估准确率,越大越好),第二、三列为标准差(看这个评估稳定性,越小越好)、方差(仅供参考)。
可以知道,对于当前的模型、参数和数据,SVM算法最优。

为了便于观察计算结果,导入matplotlib.pyplot包,在最后添加下面的代码画出箱子图。

1
2
plt.boxplot(cv_results,labels =names)  
plt.show()

输出图形:
其中矩形框表示大部分数值的范围,最下面的横线是最小值,最大值由于和矩形框重叠没有显示,橙色线条为中位数。
容易看出SVM算法最稳定(中位数最高且没有数据在框外)
image.png

更换数据

把数据改为数字识别数据

1
X,y = datasets.load_digits(return_X_y=True)

结果发现KNN效果最好。
image.png
但是问题是:KNN算法太慢,因为:

  1. 每次必须等到test data过来才能计算。
  2. 每次计算要使用这一个test data遍历它到train data中每个data的距离。根据test data到所有train data的距离,找到train data中最匹配的data,取它的label作为y_pred。
    结合以上两点,因此用时很久。

优化方案是:
提前计算好每个可能的test data的y_pred,将(data, y_pred)存储起来。下次使用时直接使用test data去匹配库中的数据data,直接找到对应的y_pred。

Confusion Matrix

前面iris的图中,假如有一个算法的boxplot和SVM算法一样时如何解决?
可以使用Confusion Matrix。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.datasets import load_iris  

from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix

X,y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.25)

svm = SVC()
svm.fit(X_train, y_train)
y_pred = svm.predict(X_test)
print(accuracy_score(y_test, y_pred))
print(y_test)
print(y_pred)
print(confusion_matrix(y_test, y_pred))

输出结果:

0.9736842105263158
[2 0 0 2 0 1 0 1 1 1 0 0 1 1 2 0 2 2 0 0 0 2 0 2 2 0 1 2 1 0 2 1 0 1 0 2 2 2]
[2 0 0 2 0 1 0 2 1 1 0 0 1 1 2 0 2 2 0 0 0 2 0 2 2 0 1 2 1 0 2 1 0 1 0 2 2 2]
[[15 0 0]
[ 0 9 1]
[ 0 0 13]]

有时候结果完全正确,此时得到的confusion_matrix是对角矩阵:

1.0
[2 0 0 1 0 2 2 0 1 0 2 1 2 0 2 1 1 0 0 1 0 0 2 2 0 1 2 2 1 2 2 1 2 0 1 2 2 1]
[2 0 0 1 0 2 2 0 1 0 2 1 2 0 2 1 1 0 0 1 0 0 2 2 0 1 2 2 1 2 2 1 2 0 1 2 2 1]
[[12 0 0]
[ 0 11 0]
[ 0 0 15]]

因为label的取值有3种0,1,2,因此得到3*3矩阵。如果是2种取值,则是2*2矩阵。
confusion matrix含义:

  • 对于第i列,每一列的数据和是正确结果为i的个数
  • 对于第i列,每一列的数据和是实际结果为i的个数

image.png

图中:
实际结果为0、1、2的个数都是10,具体为10, 10, 1+9
预测结果为0、1、2的个数分别是10、11(10+1)、9。
可以得知预测结果多了1个1的结果,少了1个2的结果,说明有一个正确结果为2的数据被错误判断为1。

一般来讲,执行到计算平均值、方差、标准差就可以了,计算Confusion Matrix属于进阶操作。

具体Confusion Matrix的用处?
Confusion Matrix可以用来查看错误的分布情况,比如方差同样是0.12的2个算法A和B,A算法是3个选项各错了约1/3,错误均匀分布在各个选项;B算法是全部错误都集中在1个选项。举个例子就是,2个同学英语成绩相同,但是一个错听力比较多,一个主要错阅读题。(从方差/标准差只能得出偏离程度,不能看出具体哪里偏差。)

为什么以及如何学机器学习

image.png
过去的是一行一行代码,可预测、具有确定性,但是发展方向是算法+数据。

学习路径:
哪怕每天看一两页、一周研究一个算法也可以(储备工具箱中工具)。不要走错方向。
https://scikit-learn.org/stable/index.html

数据分析方向基础能力

主要是3种能力:

  • Coding
  • Maths
  • English

具体来说,课后这个方向要做的是:

  • 研究各个算法(课堂只用了KNN等)具体干了些什么,而不只是使用。拓宽广度为工作服务,但暂时先不必研究深度,后期如果研究透了再研究。
  • 学习过程中多看ML相关英文资料。

目前(2023.8)来说,国内机器学习方面主要是大厂招人做研究,更偏向学术一点,因此岗位很少,而且要求很高。但是美国已经开始了这样的应用,目前国内的发展进程大概是美国10年前的样子。按照美国的发展经验,后面再过几年(5年?)也会开始大规模应用,到时候相关岗位会很多,而且也不会要求这么高。