课程目录 小象学院 - 人工智能
关注公众号【Python家庭】领取1024G整套教材、交流群学习、商务合作。整理分享了数套四位数培训机构的教材,现免费分享交流学习,并提供解答、交流群。
你要的白嫖教程,这里可能都有喔~
今天来自码农届最会品酒的一位老司机将出山,带你挑选上好的葡萄酒,亲授独门绝技,包学包会(老司机膨胀了^_^)
平时如果你喜欢喝点小酒儿,但是对如何挑选葡萄酒不是很在行的话,学习完本关课程你将成为码农届最会品酒的葡萄酒鉴赏“砖”家,凭这一关值回票价(老司机膨胀 +2)
下面有请老司机闪耀出厂(哼哼哈嘿~)
案例引入:挑选葡萄酒
根据老司机多年的品酒经验来看,鉴别一瓶红酒品质的好坏要用一个具体的指标来衡量,通常使用“质量”(quality)来衡量一瓶红酒品质的好坏。
注意了,这里说的质量不是一个物体的重量,也不是我们平时理解的物理意义上的质量,在红酒的鉴别过程中,就把它理解成一个评分就好了!
影响红酒质量的因素有很多,如:气候、温度、湿度、葡萄品种、酿造工艺等。
如果要通过指标给一款红酒的质量划分等级,可以通过一些关键的理化指标来衡量,如:酒精含量、含糖量、含酸量等。
是时候该祭出我的82年雪碧青春版啦(哈利路亚~)
老司机虽然经验丰富,但是没有数据支持也只是单纯的年龄大,白瞎一身武功无处施展(快使用双节棍!哼哼哈嘿!老司机疯了~)
接下来按照机器学习项目的开发流程,开始老司机的手把手教学(走起!来左边跟我一起画个龙,在你右边再画一道彩虹......)
收集数据
step1. 收集数据
老司机“托关系”搞到了一批有关红酒的数据,数据集存储在CSV文件中,文件名称:winequality-red.csv(数据集来自kaggle)。
红酒数据集中共有1599个样本数据(也就是有1599瓶红酒的数据),每个样本有12列,前11列表示一个样本的11个特征。最后1列”quality”表示红酒的质量,质量值是0到10之间的整数,值越大表示这瓶红酒的质量越好,红酒的等级越高。
由于最后一列"quality"的值是0到10之间的整数,那么我们可以把每一个整数值看做是一个类别,也就是一个数字表示一种红酒的类别。
样例数据:
每列数据含义:
目前我们手上已经掌握了数据,并且非常清晰地理解了数据内容,接下来进行下一步。
准备数据
step2. 准备数据
人狠话不多,先上代码
AI_6_0_1
import pandas as pd
# 加载数据集
winequality_red_df = pd.read_csv("../data/winequality-red.csv")
winequality_red_df.to_csv('../../tmp/hahaha.csv')
# 使用python提供的type函数查看变量winequality_red_df的类型是DataFrame
print(type(winequality_red_df))
<class 'pandas.core.frame.DataFrame'>
解释下上面的代码:虽然使用Python原生代码可以读取CSV文件中的内容,但是代码还是不够简洁。
Pandas给我们提供了读取CSV文件更加简便的方法,使用Pandas内置的read_csv函数读取样本数据集winequality-red.csv。
查看数据集的结构,DataFrame内置了shape属性,shape返回一个数组,数组中的第1个元素(下标从0开始)表示样本个数(行数),第2个元素表示样本列数。
AI_6_0_2
import pandas as pd
# 加载数据集
winequality_red_df = pd.read_csv("../data/winequality-red.csv")
# 通过DataFrame的shape属性查看数据集结构
print("winequality_red_df中样本行数:{},列数:{}".format(winequality_red_df.shape[0],winequality_red_df.shape[1]))
winequality_red_df中样本行数:1599,列数:12
通过上面代码的运行结果,我们知道已读取的数据集中有1599个样本,每个样本有12列数据。
我们了解了数据集的结构之后,再查看下具体样本内容。由于数据集中样本量比较大,我们只需要查看前几行数据即可。
AI_6_0_3
import pandas as pd
# 加载数据集
winequality_red_df = pd.read_csv("../data/winequality-red.csv")
# 查看数据集部分数据内容,head默认打印前5行数据
print(winequality_red_df.head())
fixed acidity volatile acidity citric acid residual sugar chlorides \
0 7.4 0.70 0.00 1.9 0.076
1 7.8 0.88 0.00 2.6 0.098
2 7.8 0.76 0.04 2.3 0.092
3 11.2 0.28 0.56 1.9 0.075
4 7.4 0.70 0.00 1.9 0.076
free sulfur dioxide total sulfur dioxide density pH sulphates \
0 11.0 34.0 0.9978 3.51 0.56
1 25.0 67.0 0.9968 3.20 0.68
2 15.0 54.0 0.9970 3.26 0.65
3 17.0 60.0 0.9980 3.16 0.58
4 11.0 34.0 0.9978 3.51 0.56
alcohol quality
0 9.4 5
1 9.8 5
2 9.8 5
3 9.8 6
4 9.4 5
经过前面的几步操作,我们对已有的数据集里包含的内容已经非常清楚了。
在机器学习项目的开发过程中,理解数据是非常重要的一个环节,只有理解透数据,才能够“因材施教”,选择合适的算法模型,最终达到比较好的预测效果。
接下来我们要做的另外一件重要的事情是将已经准备好的数据集分成训练数据集和测试数据集两部分。
还记得训练数据集和测试数据集的作用吗?
忘记了也没关系,我在这里再啰嗦几句,让我们再重温下这两个数据集的作用。
训练数据集:用于训练算法模型,指导模型应该如何调整自己的参数。
测试数据集:用于测试算法模型的预测结果是否符合预期,也就是把测试数据输入给已经训练好的算法模型,看看模型预测的结果与真实值之间的差距。
下面开始划分测试数据集与训练数据集
通常情况下,测试数据集与训练数据集按照2:8的比例划分,两种数据集都包含特征和目标变量(类别)两部分,使用小写字母x表示特征集,小写字母y表示目标变量(类别)集,这两个集合中的每一条数据都是一一对应的。
例如:x特征集中的第一条数据与y目标变量集的第一条数据组合在一起就是第一条完整的样本数据。
也就是说,不论是测试数据集,还是训练数据集,在实际操作的时候,各自又分成两部分。
AI_6_0_4
import pandas as pd
# 引入sklearn提供的划分数据集的train_test_split函数
from sklearn.model_selection import train_test_split
import numpy as np
# 加载数据集
winequality_red_df = pd.read_csv("../data/winequality-red.csv")
print('**************************************************************************')
print(type(winequality_red_df))
# 提取样本数据集
x = winequality_red_df[["fixed acidity","volatile acidity","citric acid",
"residual sugar","chlorides","free sulfur dioxide",
"total sulfur dioxide","density","pH","sulphates","alcohol"]]
# 提取样本数据集的中的quality列组成目标变量集,这一列表示每瓶红酒(每个样本)的质量(表示等级高低的值)
y = winequality_red_df["quality"]
# 把dataframe类型转换成我们熟悉的numpy中的数组
x = np.array(x)
print(type(x))
y = np.array(y)
print(type(y))
# 划分训练数据集与测试数据集,测试数据集占整个数据集的20%
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
print("整个数据集样本数:{}".format(len(x)))
print("x_train个数:{},y_train个数:{}".format(len(x_train), len(y_train)))
print("x_test个数:{},y_test个数:{}".format(len(x_test), len(y_test)))
**************************************************************************
<class 'pandas.core.frame.DataFrame'>
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
整个数据集样本数:1599
x_train个数:1279,y_train个数:1279
x_test个数:320,y_test个数:320
使用sklearn提供的train_test_split函数将原始数据集划分成4个子集:
-
x_train:表示训练样本特征的集合;
-
y_train:表示训练样本目标变量(类别)的集合;
x_train和y_train都属于训练数据集。
-
x_test:表示测试样本特征的集合;
-
y_test:表示测试样本目标变量(类别)的集合;
x_test和y_test都属于测试数据集。
虽然把训练数据集和测试数据集分别又分成了特征和目标变量两个子集,但是同一类数据集内的特征集中的一条样本特征与目标变量集中的一个样本类别是一一对应的。
容我再啰嗦几句,介绍下train_test_split函数的使用方法:
train_test_split函数是sklearn库中内置的函数,我们可以直接使用它对数据集进行划分,通常在调用train_test_split函数的时候会传入4个参数。
例如:train_test_split(x, y, test_size=0.2, random_state=0)
参数的详细描述如下: 参数1 x:原始样本数据集中的特征集,由所有样本的特征组成。 参数2 y:原始样本数据集中的标签集,由所有样本的类别标签(目标变量)组成。 参数3 test_size:这个参数可以被传入浮点数或者整数值,如果传入是0到1之间的浮点数,表示测试样本集在原始数据集中的占比。如果参数值是整数,表示测试样本集中样本的数量。 参数4 random_state:随机数种子,可以甚至任意值。它的作用是在重复试验的场景下,如果需要随机划分训练集和测试集,在train_test_split函数其他参数值不变的情况下,重复调用这个函数,每次划分的结果是一样的。也就是说通过设置random_state参数值,可以保证多次重复试验使用的训练数据集和测试数据集不变。
模型选择
step3. 选择模型
我们通过前面两步的操作,已经把数据准备好了。接下来进入了选择模型的阶段,通常情况下我们需要根据业务员场景、数据特征来选择合适的模型。
我们目前要解决的是分类问题,要根据红酒的特征给它划分等级(1-10之间的整数,每个数字代表一个等级)。
我们目前已经学习的k近邻算法正好可以解决分类问题,那么这里我们选择使用k近邻算法来解决红酒等级划分的这个分类问题。
AI_6_0_5_引入sklearn中的k近邻算法KNeighborsClass
# 引入sklearn中的k近邻算法KNeighborsClassifier
from sklearn.neighbors import KNeighborsClassifier
# 设置k的初始值为5
k = 5
# 创建kNN模型对象
knn = KNeighborsClassifier(n_neighbors=k)
根据KNeighborsClassifier类创建一个k近邻算法对象kNN对象,然后我们随机给k设置一个初始值5,后面就可以直接使用kNN对象进行模型的训练和预测。
训练模型
step4. 训练模型
调用上面已经创建好的k近邻算法实例对象kNN的fit方法训练模型,在sklearn机器学习算法包中不只k近邻算法有fit方法,其他的一写算法模型也提供了fit方法,fit方法主要用于模型的训练。
使用fit方法训练模型的时候,需要传入训练数据集,我们知道训练数据集被划分成了两部分:特征集x_train和标签集y_train,所以要把这两个数据集作为参数传入到fit方法中。
AI_6_0_6
from sys import path
path.append(r"../data/course_util")
from ai_course_6_1 import *
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
k = 5
# 创建kNN模型对象
knn = KNeighborsClassifier(n_neighbors=k)
# 训练模型
knn.fit(x_train, y_train)
老司机温馨提示:k近邻算法是机器学习中唯一一个不需要训练过程的算法,也可以认为训练数据集就是模型本身。
为什么说k近邻算法不需要训练呢?
因为k近邻算法的核心原理是:对于一个未知分类的样本(一个新的样本只有特征没有所属类别标签),如果使用k近邻算法预测该未知样本的所属分类的话,要先求出未知样本与已知样本之间的距离,然后从距离最近的k个已知样本中找出占比最多的类别,这个占比最多的类别就是kNN对未知样本的预测结果。
到这里我们知道了k近邻算法的精髓就是求距离和占比,所以k近邻算法不需要训练,当来了一个待预测的新样本时,只需要计算出与已知样本的距离和占比即可。
有同学会问:既然k近邻算法不需要训练,那为什么还要调用fit方法训练模型呢?
原因是:为了保证所有的机器学习项目开发流程标准化,所有的机器学习项目都是类似的开发过程。
让我们继续往下走~
测试模型
step5. 测试模型
好啦,经过上一步操作,k近邻算法模型已经训练好了!
你说好就好呀,你这是王婆卖瓜自卖自夸,谁知道你有没有什么猫腻呢?
我得用我的测试样本测试下你这个模型,看看是不是符合我的预期。
准备已久的测试数据集终于派上了用场,那么我就调用kNN对象的predict方法,传入测试特征集,开始预测预测
AI_6_0_7
from sys import path
path.append(r"../data/course_util")
from ai_course_6_1 import *
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
k = 5
# 创建kNN模型对象
knn = KNeighborsClassifier(n_neighbors=k)
# 训练模型
knn.fit(x_train, y_train)
# 训练好的模型使用测试数据集进行预测
y_pred = knn.predict(x_test)
print(y_pred) #打印预测结果
[5 5 7 6 6 5 6 6 6 5 5 5 5 5 5 5 7 6 5 5 7 6 6 5 6 5 6 6 5 6 6 5 6 5 6 6 5
6 6 6 6 6 6 5 5 6 5 6 5 6 6 5 5 7 5 5 5 5 7 5 5 6 6 5 5 5 5 7 7 7 5 5 5 5
6 6 5 6 5 6 5 5 4 6 5 5 5 5 6 5 5 5 5 5 4 5 5 6 5 5 7 5 5 6 6 6 6 6 6 5 6
5 6 6 5 6 5 7 7 6 5 7 5 5 7 5 5 5 5 5 5 5 5 5 6 5 6 5 6 5 6 5 5 5 5 6 6 7
5 6 5 5 6 6 5 6 5 6 6 6 5 6 5 6 6 5 6 5 6 5 5 7 6 7 5 6 5 7 6 5 5 6 6 6 6
5 6 5 5 6 5 5 5 5 5 5 5 5 5 5 6 6 6 6 5 5 6 6 6 5 5 5 5 5 5 5 5 6 5 5 5 5
7 6 6 5 5 5 6 4 5 6 5 5 7 6 6 6 5 6 6 5 6 6 5 5 5 5 5 5 5 6 5 5 5 5 5 6 5
7 5 6 5 5 5 5 6 5 6 5 5 5 6 5 6 6 5 6 6 7 6 6 5 5 5 5 5 5 6 5 5 5 5 6 5 6
5 5 5 5 6 5 7 5 5 6 5 5 6 5 5 6 5 6 6 7 5 6 5 7]
预测结果中的每一个数字表示一个测试样本的预测值,也就是一瓶红葡萄酒的级别。
有了预测结果,到底预测的准确不准确呢?让我们使用准确率来衡量k近邻算法的预测效果。
准确率 = 预测正确的结果数 / 真实值样本数
这里使用sklearn提供的accuracy_score函数计算准确率,该函数需要传入两个参数:
-
第1个参数:测试样本集的标签集y_test;
-
第2个参数:模型的预测结果集y_pred。
AI_6_0_8
from sys import path
path.append(r"../data/course_util")
from ai_course_6_1 import *
from sklearn.metrics import accuracy_score
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
k = 5
# 创建kNN模型对象
knn = KNeighborsClassifier(n_neighbors=k)
# 训练模型
knn.fit(x_train, y_train)
# 训练好的模型使用测试数据集进行预测
y_pred = knn.predict(x_test)
# 计算准确率
acc = accuracy_score(y_test, y_pred)
print("准确率:", acc)
准确率: 0.48125
从计算出来的准确率可以看出,当k=5时,k近邻算法模型的预测结果准确率约等于0.48,准确率不是很高,老司机不是很满意。
老司机摇了摇头,准备使出他的洪荒之力攻克这个难题!
老司机猜测可能是k值的问题,决定用50个不同的k值分别测算准确率,看看哪个k值的准确率更高。
为了更加直观的观察对比结果,在测试过程中使用Matplotlib在二维平面上绘制出一个折线图,X轴是k值,Y轴是准确率,通过折线图走势观察k值对模型预测结果的影响。
我们专门定义一个在二维平面上绘制折线图的函数search_grid_best_k。
AI_6_0_9
from sys import path
path.append(r"../data/course_util")
from ai_course_6_2 import *
%matplotlib inline
import matplotlib.pyplot as plt
# 新定义的在二维平面上绘制折线图的函数
def search_grid_best_k(k_start,k_end):
# 存储k_start到k_end 不同的k值
k_range = range(k_start, k_end)
# 存储不同k值模型的准确率
acc_scores = [ ]
# 存储准确率最高的k值
best_k = -1
# 存储最高的准确率值
best_score = 0
# 通过网格搜索找到准确率最高的k值
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
# 使用训练样本集训练模型
knn.fit(x_train, y_train)
# 由于我们不需要查看预测结果,只想知道每个k值对应的准确率,所以直接调用sklearn提供的score函数,计算预测结果准确率
# 相当于把先预测再计算准确率这两步操作合并成了一步
# y_pred = knn.predict(x_test)
# score = accuracy_score(y_test, y_pred)
score = knn.score(x_test, y_test)
# 如果本次实验得到的准确率高于以往的最好值,则更新best_k和best_score
if score > best_score:
best_k = k
best_score = score
acc_scores.append(score)
print("best_k = ",best_k)
print("best_score = ",best_score)
# 根据不同k值的准确率画折线图,横轴为k值,纵轴为准确率
# 使用matplotlib画图
plt.figure()
# 设置图片大小
plt.rcParams["figure.figsize"] = (15.0, 8.0)
# 设置x轴显示的标签名是k
plt.xlabel("k")
# 设置y轴显示的标签名是accuracy
plt.ylabel("accuracy" )
# X轴坐标表示k值,Y轴坐标表示准确率
plt.plot(k_range, acc_scores, marker="o")
# 设置X轴上显示的坐标值,由于k值比较多,每一个值都显示在X轴上不方便看,所以我们隔5个数在X轴上显示一个数字
plt.xticks(range(0,k_end,5))
plt.show()
# 调用自定义的画折线图函数
search_grid_best_k(1,51)
best_k = 1
best_score = 0.609375
从本次实验结果来看,当k=1时,准确率达到了最高值约等于0.61,比上一次实验的0.48高了不少。
此时,老司机嘴角露出了一丝丝微笑,十分得意的说:通过本次实验证明我是对的!!!
我现在郑重宣布:在k近邻算法中,k值对预测结果的影响是非常明显滴!是我们重点关注的一个超参数!
虽然老司机比较容易嘚瑟,但是他还是很有科研精神的。虽然他已经取得了“重大”(根本不算啥,嘿嘿~)突破,但是他还想再进一步提高准确率!
老司机又提出了一个假设:之前的实验都是基于样本的所有特征进行的,那么样本特征对模型准确率是不是也有影响呢?会不会只有一部分特征对准确率影响是比较大的呢?
带着这样的假设,老司机又上路(做实验)了......
老司机打算从已有的样本数据入手,看看会不会有没有新的发现^_^
通过对数据的观察,老司机还真有了一些新的发现,同一个样本的有些特征值不在同一个量纲下,也可以理解成不在一个数量级范围内,比如第7列二氧化硫和第8列密度这两列的值差距很大。
第7列total sulfur dioxide二氧化硫的取值范围是:[6,289],而第8列density密度的取值范围是:[0.99007,1.00369]
AI_6_0_10
import pandas as pd
import numpy as np
# 加载数据集
winequality_red_df = pd.read_csv("../data/winequality-red.csv")
# 提取样本数据集
x = winequality_red_df[["fixed acidity","volatile acidity","citric acid",
"residual sugar","chlorides","free sulfur dioxide",
"total sulfur dioxide","density","pH","sulphates","alcohol"]]
# 提取样本数据集的中的quality列组成目标变量集,这一列表示每瓶红酒(每个样本)的质量(表示等级高低的值)
y = winequality_red_df["quality"]
# 把dataframe类型转换成我们熟悉的numpy中的数组
x = np.array(x)
y = np.array(y)
# 查看样本数据集中第7列二氧化硫的最大值和最小值
print("二氧化硫的最大值: ",np.max(x[:,6])) # 因为下标从0开始,所以第7列的下标是6
print("二氧化硫的最小值: ",np.min(x[:,6]))
# 查看样本数据集中第8列密度的最大值和最小值
print("密度的最大值: ",np.max(x[:,7]))
print("密度的最小值 : ",np.min(x[:,7]))
print('*****************************************************')
x
二氧化硫的最大值: 289.0
二氧化硫的最小值: 6.0
密度的最大值: 1.00369
密度的最小值 : 0.99007
*****************************************************
如果只选择数据集中的二氧化硫和密度两个特征作为样本之间计算距离的特征,那么通过kNN算法对新样本进行预测的时候,在计算距离的过程中,由于二氧化硫和密度这两个特征值的差距非常悬殊,最终样本的距离会被二氧化硫这个特征值所主导,密度这个特征几乎没有起到作用。
例如,选择一个新的样本的二氧化硫和密度两个特征(55,0.99745)与已知样本(289,0.99316)之间的距离如下:
AI_6_0_11_导入开平方函数sqrt
# 导入开平方函数sqrt
from math import sqrt
# 计算上面说的一个新的样本的二氧化硫和密度两个特征(55,0.99745)与已知样本(289,0.99316)之间的距离
sqrt((55-289)**2 + (0.99745-0.99316)**2)
234.000000039325
通过上面的计算结果可以看出,最终的结果几乎会等于234,因为两个样本的密度值相减之后的值0.00429与二氧化硫相减之后的值234悬殊很大,然后又做了一次平方操作进一步缩小了密度差值对最终结果的影响,这样就不能非常好地反映出每一个特征的重要程度!
为了解决上面说的量纲的问题,为了让样本的每个特征都被公平对待,为了每个特征都能充分发挥它的价值。
归一化处理
我们需要对样本数据集进行处理,这个处理的过程叫做归一化处理!
什么叫归一化处理呢?通俗的讲就是使样本的每个特征值都处在同一个尺度上,比如:让所有特征值都在0到1之间。
归一化处理是老司机的拿手“菜”,老司机在做菜之前要先选择一把好刀(选择一个好的处理方法),最终老司机选择了“最值归一化”这把锋利的宝刀。
最值归一化公式
经过最值归一化处理过的数据都会落在0到1之间,通过一个公式就可以明白最值归一化的详细计算过程:
xscalex_{scale}xscale表示经过最值归一化处理之后的特征值;
xxx表示一个样本的一个特征值,也就是通过最值归一化要处理的那个特征;
xminx_{min}xmin 表示样本数据集中,一列特征的最小值;
xmaxx_{max}xmax表示样本数据集中,一列特征的最大值。
最值归一化代码实现
我们已经明白了最值归一化的计算过程,接下来用python代码实现使用最值归一化处理样本数据集的所有特征。
AI_6_0_12
from sys import path
path.append(r"../data/course_util")
from ai_course_6_3 import *
print("最值归一化之前的原始数据:")
print(x[:5,:]) #打印前5条数据
# 使用最值归一化处理样本的所有特征,使特征值最终落在0-1之间
# x是样本特征集,array数组类型,通过array的的属性shape[1]获得数据集的列数(也就是样本具有的特征数量)
# 因为要对样本的所有特征进行处理,所以使用for循环遍历每一列特征
for n in range(0,x.shape[1]):
# 对第n列做归一化处理
x[:,n] = (x[:,n] - np.min(x[:,n])) / (np.max(x[:,n]) - np.min(x[:,n]))
print("最值归一化之后的数据:")
print(x[:5,:])
经过最值归一化之后,所有特征的值都落在了0-1之间,这样所有的特征值就就有了相同的量纲(同一个尺度)。
使用规划化之后的样本数据集,重新划分数据集:
AI_6_0_13
from sys import path
path.append(r"../data/course_util")
from ai_course_6_4 import *
from sklearn.model_selection import train_test_split
# 划分训练数据集与测试数据集,测试数据集占整个数据集的20%
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
划分好数据集之后,调用之前定义的search_grid_best_k函数,寻找k的最优解:
AI_6_0_14
from sys import path
path.append(r"../data/course_util")
from ai_course_6_5 import *
%matplotlib inline
# 调用自定义的画折线图函数
search_grid_best_k(1,51)
best_k = 1
best_score = 0.646875
从本次实验结果来看,当k=1时,准确率达到了最高值约等于0.65,比上一次实验的0.61又提高了一些。虽然实验结果还不是理想,但是我们通过这个项目已经掌握了机器学习项目的开发流程,掌握了在遇到问题时,应该怎样解决问题方法。
就在此时此刻,老司机又要登场了,要对这个项目做个总结:
机器学习项目开发流程:
-
收集数据
-
准备数据
-
选择算法模型
-
训练模型
-
测试模型
最值归一化详细原理及计算公式:
经过最值归一化处理过的数据都会落在0到1之间
老司机今天的表演结束了,感谢捧场^_^
联系我们,一起学Python吧
分享Python实战代码,入门资料,进阶资料,基础语法,爬虫,数据分析,web网站,机器学习,深度学习等等。
关注公众号「Python家庭」领取1024G整套教材、交流群学习、商务合作