机器学习入门基础(一)

机器学习简介

  • 祖师爷
    • 图灵,人工智能之父,最大成就图灵测试,就是一个机器和一个人跟你聊天,你不知道对方是人还是机器,如果经过聊天后,你分辨不出谁是人谁是机器说明这个机器通过了图灵测试。
  • 人工智能和机器学习的区别?
    • 机器学习就是实现人工智能的一种手段
  • 什么是机器学习?
    • 机器学习就是从【数据】自动分析获得【规律(模型)】,并利用规律对未知数据进行【预测】。
  • 老师的理解
    • 模型:
      • 算法模型,是一个特殊的对象。该算法模型对象中已经集成或者封装好了某种形式的方程、算法。(还没有求出解的方程)
    • 模型的作用:
      • 预测:可以通过方程或者算法产生一个新的未知的数据 / 事务
      • 分类:可以将一个未知归类的事务给其归属到一个已有的类群中
      • 注意:算法模型对应的算法或方程求出的解就是预测或分类的结果。
    • 样本数据
      • 模型的训练:将样本数据带入到模型中,对其进行训练(给方程进行求解操作),模型训练好了之后,则模型的方程就有了唯一的解或者最优解。有解后模型就可以实现分类或者预测的功能。
      • 构成:
        • 特征数据:自变量(楼层、面积、采光率)
        • 标签 / 目标数据:因变量(售价)
        • 例子:
楼层        采光率			面积				售价
 3			55%				100				200w
 5			88%				100				315w
......
  • 模型的分类
    - 有监督学习
    - 如果模型需要的样本数据必须包含特征数据和标签数据,则该模型为有监督学习分类
    - 半监督学习
    - 无监督学习
    - 模型需要的样本数据只需要有特征数据即可,目标数据有或者无都可以。
    • 样本数据(数据集)的载体:
      • 通常情况下历史数据不会存储在数据库中,而是存储在文件中(csv文件)
      • 数据库存储数据存在的问题:
        • 性能瓶颈:数据量级大的数据很难存储和进行高效的读写。
        • 数据存储格式不符合机器学习要求的数据格式
    • 样本数据获取的途径:
      • kaggle:数据竞赛平台
      • UCI数据集:是一个常用的机器学习标准测试数据集,是加州大学欧文分校提出的用于机器学习的数据库
      • sklearn

特征工程

  • 特征提取

  • 数据特征的预处理

  • 特征选择

  • 为什么需要特征工程 ?

    • 样本数据中的特征可能存在缺省值,重复值,异常值等等,那我们是需要对特征中的相关的噪点数据进行处理的,那么处理的目的就是为了营造一个更纯净的样本集,让模型基于这组数据有更好的预测能力。当然特征工程不是单单只处理上述操作。
  • 什么是特征工程?

    • 特征工程是将原始数据转换为更好的代表预测模型的潜在问题的特征的过程,从而提高未知数据预测的准确性
    • 特征工程的意义:
      • 直接影响模型预测的结果
    • 如何实现特征工程
      • 工具:sk-learn
    • sk-learn介绍
      • 是python语言中的机器学习工具,包含了很多机器学习算法的实现,其文档完善,容易上手。
      • 功能:
        • 分类模型
        • 回归模型
        • 聚类模型
        • 特征工程
  • 特征提取

    • 目的:
      • 我们所采集到样本中的特征数据往往很多时候为字符串或者其他类型的数据,我们知道电脑可以识别二进制数值型的数据,机器学习的数据需要的数值型的数据进行学习。
      • 效果演示
        • 将字符串转换成数字
          In [2]:
	from sklearn.feature_extraction.text import CountVectorizer
	vector=CountVectorizer()
	res=vector.fit_transform(['lift is short,i love python','lift is too long,i hate python'])
	print(res.toarray())
	#输出结果 
	[[0 1 1 0 1 1 1 0]
 [1 1 1 1 0 1 0 1]]
  • 演示后的结论
    • 特征抽取对文本数据进行特征值化。特征值为了让机器更好的理解数据。
  • 字典特征提取
    -作用:对字典数据进行特征值化
    -api: from sklearn.feature_extraction.text import DictVectorizer
    -fit_transform(x):x为字典或者包含字典的迭代器,返回值为sparse矩阵
    -inverse_transform(x):x为sparse矩阵或者array数组,返回值为转换之前的数据格式
    -transform(x):按照原先的标准转换
    -get_feature_names():返回类别名称
    In [3]:
from sklearn.feature_extraction import DictVectorizer

alist = [{'city': 'BeiJing', 'temp': 33}, {'city': 'GZ', 'temp': 42}, {'city': 'SH', 'temp': 40}]
# 实例化一个工具类对象
d = DictVectorizer()
# 返回的是一个sparse矩阵(存储的就是特征值化的结果)
feature = d.fit_transform(alist)
print(feature)
# 输出结果: 
  (0, 0)	1.0
  (0, 3)	33.0
  (1, 1)	1.0
  (1, 3)	42.0
  (2, 2)	1.0
  (2, 3)	40.0
  • 什么是sparse矩阵?
    • 在DictVectorizer类的构造方法中设定sparse=False则返回的就不是sparse矩阵,而是一个数组。
    • sparse矩阵就是一个变相的数组或者列表,目的是为了节省内存
      In [5]:
from sklearn.feature_extraction import DictVectorizer

alist = [{'city': 'BeiJing', 'temp': 33}, {'city': 'GZ', 'temp': 42}, {'city': 'SH', 'temp': 40}]
d = DictVectorizer(sparse=False)
# 返回的是一个sparse矩阵(存储的就是特征值化的结果)
feature = d.fit_transform(alist)
print(d.get_feature_names())
print(feature)
# 输出结果:1为是,0为不是
['city=BeiJing', 'city=GZ', 'city=SH', 'temp']
[[ 1.  0.  0. 33.]
 [ 0.  1.  0. 42.]
 [ 0.  0.  1. 40.]]
  • OneHot编码
    • sparse矩阵中的0和1就是OneHot编码
    • 为什么需要OneHot编码呢?
      • 特征抽取主要目的就是对非数值型的数据进行特征值化!
        机器学习入门基础(一)
        机器学习入门基础(一)
  • 基于pandas实现OneHot编码
    • pd.get_dummies(df[‘col’])
      In [7]:
import pandas as pd

df = pd.DataFrame([['green', 'M', 20, 'class1'],
                   ['red', 'L', 21, 'class2'],
                   ['blue', 'XL', 22, 'class3']])
df.columns = ['color', 'size', 'weight', 'class label']
print(df)
print(pd.get_dummies(df['color']))
# 输出结果:
   color size  weight class label
0  green    M      20      class1
1    red    L      21      class2
2   blue   XL      22      class3

   blue  green  red
0     0      1    0
1     0      0    1
2     1      0    0

  • 文本特征提取
    • 作用:对文本数据进行特征值化
    • API:from sklearn.feature_extraction.text import CountVectorizer
    • -fit_transform(x):x为文本或者包含文本字符串的可迭代对象,返回sparse矩阵
      -inverse_transform(x):x为sparse矩阵或者array数组,返回值为转换之前的数据格式
      -toarray():将sparse转换成数组
      -get_feature_names():返回类别名称
      In [6]:
from sklearn.feature_extraction.text import CountVectorizer
	vector=CountVectorizer()
	res=vector.fit_transform(['lift is short,i love python','lift is too long,i hate python'])
	print(res)
	print(vector.get_feature_names())
	print(res.toarray())#将sparse矩阵转换成数组
	# 单字母不统计(因为单个字母代表不了实际含义),然后每个数字表示的是单词出现的次数
	# 输出结果:
	(0, 2)	1
  (0, 1)	1
  (0, 6)	1
  (0, 4)	1
  (0, 5)	1
  (1, 2)	1
  (1, 1)	1
  (1, 5)	1
  (1, 7)	1
  (1, 3)	1
  (1, 0)	1
['hate', 'is', 'lift', 'long', 'love', 'python', 'short', 'too']
[[0 1 1 0 1 1 1 0]
 [1 1 1 1 0 1 0 1]]
  • 中文文本特征提取
    • 对有标点符号的中文文本进行特征提取
      In [15]:
from sklearn.feature_extraction.text import CountVectorizer

vector = CountVectorizer()
res = vector.fit_transform(['人生苦短,我用python', '人生漫长,不用python'])
print(res)
print(vector.get_feature_names())
print(res.toarray())
#输出结果:
 (0, 2)	1
  (0, 3)	1
  (1, 1)	1
  (1, 0)	1
['不用python', '人生漫长', '人生苦短', '我用python']
[[0 0 1 1]
 [1 1 0 0]]
  • 对有标点符号且有空格分隔的中文文本进行特征处理
    In[8]:
from sklearn.feature_extraction.text import CountVectorizer

vector = CountVectorizer()
res = vector.fit_transform(['人生 苦短,我 用python', '人生 漫长,不用python'])
print(res)
print(vector.get_feature_names())
print(res.toarray())
# 单个汉字不统计
# 输出结果:
 (0, 1)	1
  (0, 4)	1
  (0, 3)	1
  (1, 1)	1
  (1, 2)	1
  (1, 0)	1
['不用python', '人生', '漫长', '用python', '苦短']
[[0 1 0 1 1]
 [1 1 1 0 0]]
  • 目前CountVectorizer只可以对标点符号和用分隔符对应的文本进行特征提取,显然这是满足不了我们日常需求的:
    • 因为在自然语言处理中,我们是需要将一段中文文本中相关的词语,成语,形容词…都需要提取的
  • **jieba分词 **
    • 对中文文章进行分词处理
    • pip install jieba
    • jieba分词的基本使用

In[17]:

# 基本使用:对文章进行分词
import jieba

jb = jieba.cut("我是一个好人")
content = list(jb)
print(content)
ct = ' '.join(content)
print(ct)  # 返回空格区分的词语
# 输出结果:
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\21641\AppData\Local\Temp\jieba.cache
Loading model cost 0.522 seconds.
Prefix dict has been built successfully.
['我', '是', '一个', '好人']
我 是 一个 好人
  • 特征预处理
    • 无量纲化:
      • 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求这种需求统称为将数据“无量纲化”,譬如梯度和矩阵为核心的算法中,逻辑回归,支持向量机,神经网络,使用无量纲化可以加快求解速度;而在距离类模型,譬如K近邻,K-Means聚类中,无量纲化可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响。(一个特例是决策树和树的集成算法们,对决策树不需要无量纲化,决策树可以把任意数据处理的很好。)
      • 那么预处理就是用来实现无量纲化的方式
    • 含义:特征提取后我们就获取对应的数值型的样本数据,然后就可以进行数据处理了。
    • 概念:通过特定的统计方法(数学方法),将数据转换算法要求的数据
    • 方式:
      • 归一化
      • 标准化
      • 如果认为每一个特征具有同等大小的权重都同等重要,则必须对其进行归一化处理。
      • 可以使用KNN算法对特征影响进行说明!!
    • 归一化的实现
    • 特点:通过对原始数据进行变换把数据映射到(默认为[0,1])之间
    • 公式:X’= X − m i n m a x − m i n \frac{X-min}{max-min} max−minX−min​
    •   X " = X ′ ∗ ( m x − m i ) + m i \ X"=X' * (mx-mi) + mi  X"=X′∗(mx−mi)+mi
    • 注:作用于每一列,max为一列的最大值,min为一列的最小值,那么X"为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0
  • 归一化后的数据服从正态分布
  • API:from sklearn.preprocessing import MinMaxScaler
    • 参数:feature_range表示缩放范围,通常使用(0,1)
  • 作用:使得某一个特征对最终结果不会造成很大影响

In[22]:

from sklearn.preprocessing import MinMaxScaler

mm = MinMaxScaler(feature_range=(0, 1))  # 每个特征缩放的范围
data = [[90, 2, 10, 40], [60, 5, 15, 45], [73, 3, 13, 45]]  # 三行四列
data = mm.fit_transform(data)  # x需要归一化的特征
print(data)
# 通过一列进行归一化处理 90,60,73 max=90 min=60 
# 输出结果:
[[1.         0.         0.         0.        ]
 [0.         1.         1.         1.        ]
 [0.43333333 0.33333333 0.6        1.        ]]
  • 问题:如果数据中存在的异常值较多,会对结果造成什么样的影响?
    • 结合着归一化计算的公式可知,异常值对原始数据的最大值和最小值的影响很大,因此也会影响对归一化之后的值。这个也是归一化的一个弊端,无法很好的处理异常值。
  • 归一化总结:在特定场景下最大值和最小值是变化的,另外最大最小值很容易受到异常值的影响,所以这种归一化的方式具有一定的局限性。因此,引出了一种更好的方法叫做:“标准化”。
  • 标准化的处理
    • 当数据均值中心化后,再按标准差缩放,数据就会服从均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(standardization,又称Z-score normalization)公式如下:
    • 公式:X’= x − m e a n σ \frac{x-mean}{σ} σx−mean​
    • 注:作用于每一列,mean为平均值,σ为标准差 var成为方差,var= ( x 1 − m e a n ) 2 + ( x 2 − m e a n ) 2 + … … n ( 每 个 特 征 的 样 本 数 ) \frac{(x1-mean)^2+(x2-mean)^2+……}{n(每个特征的样本数)} n(每个特征的样本数)(x1−mean)2+(x2−mean)2+……​, σ = v a r σ=\sqrt{var} σ=var ​ 其中:方差(考量数据的稳定性)
      • 从公式中可以看出,异常值对方差和标准差的影响不大
    • 归一化和标准化总结
      • 对于归一化来说,如果出现了异常值则会影响特征的最大最小值,那么最终结果会受到较大影响
      • 对于标准化来说,如果出现异常点,由于具有一定的数据量,少量 的异常点对于平均值的影响并不大,从而标准差改变比较少
    • StandardScaler和MinMaxScaler选择哪个:看情况,大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。MinMaxScaler在不涉及距离度量,梯度,协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩与[0,1]区间之中
    • 建议先看看StandardScaler,如果效果不好换MinMaxScaler
    • API
      • 处理后,每列所有的数据都聚集在均值为0,标准差为1范围附近
      • 标准化API:from sklearn.preprocessing import StandardScaler
      • fit_transform(X):对X进行标准化
      • mean_:均值
      • var_:方差

In[23]:

from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
data = [[90, 2, 10, 40], [60, 5, 15, 45], [73, 3, 13, 45]]
data = ss.fit_transform(data)
print(data)
  • 特征选择:从特征中选择出有意义的对模型有帮助的特征作为最终的机器学习输入的数据!
    • 切记:
      • 在做特征选择之前,有三件非常重要的事情:跟数据提供者联系,跟数据提供者沟通,跟数据提供者开会。
      • 一定要抓住给你提供数据的人,尤其是理解业务和数据含义的人,跟他们进行了解深入。技术能够让模型起飞,前提是你和业务人员一样了解数据。所以特征选择的第一步是根据我们的目标,用业务常识来选择特征。
    • 特征选择的原因:
      • 冗余:部分特征的相关度高,容易消耗计算机的性能
      • 噪点:部分特征对预测结果有偏执影响
    • 特征选择的实现:
      • 人为对不相关的特征进行主观舍弃
      • 当然了,在真正的数据应用领域,比如金融,医疗,电商,我们的数据特征特别多,很明显,那如果遇见极端情况,我们无法依赖对业务的理解来进行选择特征,该怎么办呢?
        • 在已有特征和对应预测结果的基础上,使用相关的工具过滤掉一些无用的或者权重较低的特征
          • 工具:
            • Filter(过滤式)
            • Embedded(嵌入式):决策树模型会选择出对其重要的特征
            • PCA降维
    • Filter过滤式(方差过滤):
      • 原理:这是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本在这个特征上基本上没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。所以无论接下来的特征工程要做什么,都要优先消除方差为0或者方差极低的特征。
      • API:from sklearn.feature_selection import VarianceThreshold
      • VarianceThreshold(threshold=x)threshold方差的值,删除所有方差低于x的特征,默认值为0表示保留所有方差非0的特征
      • fit_transform(X):X为特征

In[10]:

from sklearn.feature_selection import VarianceThreshold

# threshold方差的值,删除所有方差低于x的特征,默认值为0表示保留所有方差非0的特征
v = VarianceThreshold(threshold=3)
v = v.fit_transform([[0, 2, 4, 3], [0, 3, 7, 3], [0, 9, 6, 3]])
print(v)
#输出结果:
[[2]
[3]
[9]]
  • 如果将方差为0或者方差极低的特征去除后,剩余特征还有很多且模型的效果没有显著提升则方差也可以帮我们将特征选择【一步到位】。留下一半的特征,那可以设定一个让特征总数减半的方差阈值,只要找到特征方差的中位数,再将这个中位数作为参数threshold的值输入就好了。
    • VarianceThreshold(np.median(X.var().values)).fit_transform(X)
      • X为样本数据中的特征列

In[28]:

import numpy as np
from sklearn.feature_selection import VarianceThreshold

feature = np.random.randint(0, 100, size=(5, 10))
# print(feature)
med = np.median(feature.var(axis=0)) # axis=0代表每一列 axis=1代表每一行
v = VarianceThreshold(threshold=med)
v = v.fit_transform(feature)
print(v)
  • 方差过滤对模型的影响

    • 我们这样做了以后,对模型效果会有怎么样的影响?在这里,使用KNN算法方差过滤前和方差过滤后运行的效果和运行的时间进行对比。KNN是K近邻算法中的分类算法,其原理非常简单,是利用每个样本到其他样本点的距离来判断每个样本点的相似度,然后对样本进行分类。KNN必须遍历每个样本和每个特征,因而特征越多,KNN计算越缓慢
    • 对于KNN,过滤后的效果十分明显,准确率稍有提升,平均运行时间减少了10分钟,特征选择后算法的效率提升了1/3
    • 注意:方差过滤主要服务的对象是:需要遍历特征的算法模型。而过滤法的主要目的是:在维持算法表现的前提下,帮助算法们降低成本。
  • PCA降维(主成分分析):是一种分析,简化数据集的技术

    • 降维的维度值就是特征的种类
    • 思想:如何最好的对一个立体的物体用二维表示
      机器学习入门基础(一)
  • 第四张图片可以比较好的标识一个立体三维的水壶。但是也要清楚,用一个低纬度去表示高纬度的物体时,一定会造成一些信息的差异。可以让低纬度也能正确表示高纬度的事务,或信息差异最小。

  • 目的:特征数量达到上百,上千的时候,考虑数据的优化。使数据维度压缩,尽可能降低源数据的维度(复杂度),损失少量信息

  • 作用:可以消减回归分析或者聚类分析中特征的数量

  • PCA大致原理
    机器学习入门基础(一)

  • 红色为原始的样本特征,为二维的特征,如果降为一维,则可以将5个红色的原始特征,映射一维的线段上就变成了4个特征。

  • PCA语法:

    • from sklearn.decomposition import PCA
    • pca = PCA(n_components=none)
      • n_components可以为小数(保留特征的百分比),整数(减少到的特征数量)
      • ** pca.fit_transform(X)**
from sklearn.decomposition import PCA

# 将数据分解为较低维度的空间
# n_components可以为小数(保留特征的百分比),整数(减少到的特征数量)
pca = PCA(n_components=3)
pca = pca.fit_transform([[0, 2, 4, 3], [0, 3, 7, 3], [0, 9, 6, 3]])
print(pca)

sklearn的数据集

  • 数据集划分
  • 数据集接口介绍
  • 数据集划分
    • 前提:机器学习就是从数据中分析自动分析获得规律,并利用规律对未知数据进行预测。换句话说,我们的模型一定是要经过样本数据对其进行训练,才可以对未知数据进行预测
    • 问题:我们得到数据后,是否将数据全部用来训练模型呢?
      • 不是,因为我们如果模型(数据的规律)都是从数据中得来的,那么模型的性能评估如何进行呢?还是基于对原先数据进行预测吗?当然不是,如果模型对原先数据进行预测,由于模型(数据的规律)本来就是从该数据中获取的,所以预测的精度几乎是百分之百。所以要评估模型的好坏,需要使用一组新数据对模型进行评估。
      • 因此我们需要把原来的样本数据拆分成两部分
        • 训练集:训练模型
        • 测试集:评估模型
          • 不同类型的模型对应的评估方式是不一样的
    • 数据集划分的API
      • from sklearn.model_selection import train_test_split
      • train_test_split(x,y,test_size,random_state)参数介绍:
        • x:特征
        • y:目标
        • test_size:测试集的比例
        • random_state:打乱的随机种子
      • 返回值:训练特征,测试特征,训练目标,测试目标
  • 数据集接口介绍
    • sklearn.datasets.load_*():获取小规模的数据集
    • sklearn.datasets.fetch_*(data_home=None,subset):获取大规模的数据集,data_home表示数据集下载目录,None表示为默认值表示的是主目录/scikit_learn_data(自动创建该文件夹)下。需要从网络下载,subset为需要下载的数据集,可以为train,test,all
      In[30]
import sklearn.datasets as datasets

# # 小规模数据集
# iris = datasets.load_iris()
# print(iris)
# # 样本数据抽取
# feature = iris['data']  # 特征数据
# target = iris['target']  # 标签数据
# print(feature.shape)
# print(target.shape)
# 大规模数据集
news = datasets.fetch_20newsgroups(data_home=None, subset='all')
print(news)
  • 鸢尾花数据集拆分
    In[31]
import sklearn.datasets as datasets

#
# 小规模数据集
iris = datasets.load_iris()
# print(iris)
# 样本数据抽取
feature = iris['data']  # 特征数据
target = iris['target']  # 标签数据
# # print(feature.shape)
# # print(target.shape)
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
print(x_test.shape)

机器学习基础

  • 机器学习算法分类
  • 机器学习开发流程
  • 机器学习中的数据类型
    • 离散型数据
      • 离散变量则是通过计数方式获取的,即是要对统计的对象进行计数,增长量非固定的,如:一个地区的企业只有一家,而第二年开了十家;一个企业的职工只有10人,第二年一次招聘招来20人等
    • 连续型数据
      • 连续变量是一直叠加上去的,增长量可以划分为规定的单位,即:1,2,3······,例如:一个人的身高,他首先长到1.51,然后才能到1.52,1.53 ······
    • 注意:连续型是有规律的,离散型是无规律的
  • 机器学习算法分类
    • 分类和回归问题
      • 分类算法基于的是[目标数据]为[离散型]数据
      • 回归算法基于的是[目标数据]为[连续型]数据
      • 结论:在社会中产生的数据必然是离散型数据或者连续型数据,那么企业针对数据的需求无非是分类或者回归问题
    • 机器学习开发流程
      • 1.数据采集
        • 公司内部产生的数据
        • 与其他公式合作产生的数据
        • 购买的数据
      • 2.分析数据所对应要解决的问题或者需求,根据目标数据推断是回归还是分类问题
      • 3.数据的基本处理
        • 数据清洗
        • 合并
        • 级联等
      • 4.特征工程
        • 特征抽取
        • 特征预处理
        • 降维等
      • 5.选择合适的模型,对其进行训练
      • 6.模型的评估
      • 7.上线使用
  • 分类算法
    • KNN分类模型
      • 概念:简单的说,K-近邻算法采用测量不同的特征值之间距离方法进行分类(K-Nearest Neighbor,KNN)
        机器学习入门基础(一)机器学习入门基础(一)
  • 欧几里得距离:欧式距离是常见的距离度量,衡量的多维空间中各个点的绝对距离。公式如下:
    • d i s t ( X , Y ) = ∑ i = 1 n ( x i − y i ) 2 dist(X,Y)=\sqrt{\sum_{i=1}^n(x_i-y_i)^2} dist(X,Y)=∑i=1n​(xi​−yi​)2
  • 案例:电影分类

机器学习入门基础(一)
机器学习入门基础(一)
机器学习入门基础(一)

  • 在scitkit-learn库中使用KNN算法
  • 分类问题:
  • 鸢尾花分类实现
    In[25]:
import sklearn.datasets as datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split

# 1.捕获鸢尾花数据
iris = datasets.load_iris()
# 2.提取样本数据
feature = iris['data']  # 特征数据
target = iris['target']  # 标签数据
# 3.数据集进行拆分
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
# 4.观察数据集:看是否需要特征工程处理的需要
# print(x_train)
# 5.实例化模型对象
knn = KNeighborsClassifier(n_neighbors=2)  # n_neighbors == k
# 在KNN中k的取值不同会直接导致分类结果的不同。n_neighbors参数表示k值。k值可以叫做模型的超参数
# 模型的超参数:如果模型参数有不同的取值且不同的取值会对模型的分类或者预测产生直接的影响

# 6.使用训练集训练模型
# X:训练集的特征数据,特征数据必须是二维的
# y:训练集的标签数据
knn = knn.fit(x_train, y_train)
print(x_train.shape)
# print(knn)
# 7.测试模型:使用测试数据
# predict表示使用训练好的模型实现分类或者预测
y_pred = knn.predict(x_test)  # 模型基于测试数据返回的分类结果
y_true = y_test  # 测试集真实的分类结果
print("模型的分类结果:", y_pred)
print('真实的分类结果:', y_true)
score = knn.score(x_test, y_test)
print(score)
print(x_test[0])
n = knn.predict([[4.5, 3.3, 1.4, 0.3]])  # 未知数据进行了分类
print(n)
  • 预测年收入是否大于500k美元
    In[36]:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split

# 加载数据
df = pd.read_csv('adult.data')
# print(df)
# 样本数据的提取
target = df['salary']
feature = df[['age', 'education_num', 'occupation', 'hours_peer_week']]
# print(feature.shape)
# print(target.shape)
# 数据集拆分
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.1, random_state=2021)
# 观察特征数据看是否需要进行特征工程
# print(x_train)
occ_one_hot = pd.get_dummies(x_train['occupation'])
# print(occ_one_hot)
x_train = pd.concat((x_train, occ_one_hot), axis=1).drop(labels='occupation', axis=1)
# print(x_train)
knn = KNeighborsClassifier(n_neighbors=49).fit(x_train, y_train)
# 对测试集的特征进行one-hot编码
occ_one_hot_test = pd.get_dummies(x_test['occupation'])
x_test = pd.concat((x_test, occ_one_hot_test), axis=1).drop(labels='occupation', axis=1)
print(knn.score(x_test, y_test))
scores = []
ks = []
for i in range(5, 50):
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(x_train, y_train)
    score = knn.score(x_test, y_test)
    scores.append(score)
    ks.append(i)
score_arr = np.array(scores)
ks_arr = np.array(ks)
# %matplotlib inline

plt.plot(ks_arr, score_arr)
plt.xlabel('k_value')
plt.ylabel('score')
plt.show()
print(score_arr.max())
# 最大值的下标
print(score_arr.argmax())
# 最优k值
print(ks_arr[score_arr.argmax()])

输出图像
机器学习入门基础(一)

  • 学习曲线寻找最优的k值
  • 约会网站配对效果判定
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split

df = pd.read_csv('datingTestSet2.txt', header=None, sep='\s+')
# print(df)
feature = df[[0, 1, 2]]
target = df[3]
# print(feature)
# print(target)
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
# print(x_train)  # 观察特征数据查看是否需要进行特征工程
# 对训练集特征数据进行预处理
mm = MinMaxScaler()
m_x_train = mm.fit_transform(x_train)  # 训练集的特征数据进行归一化操作
# 对测试集的数据进行归一化处理
m_x_test = mm.transform(x_test)
# 绘制学习曲线寻最优k值
scores = []
ks = []
for i in range(3, 50):
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(m_x_train, y_train)
    score = knn.score(m_x_test, y_test)
    scores.append(score)
    ks.append(i)
score_arr = np.array(scores)
ks_arr = np.array(ks)
plt.plot(ks_arr, score_arr)
plt.xlabel('k_value')
plt.ylabel('score')
plt.show()
# 最大值
print(score_arr.max())
# 最大值的下标
print(score_arr.argmax())
# 最优k值
print(ks_arr[score_arr.argmax()])
knn = KNeighborsClassifier(n_neighbors=7).fit(m_x_train, y_train)
print(knn.score(m_x_test, y_test))
print(knn.predict([[2345, 20, 1.1]]))

  • 问题:约会数据中发现目标数据为非数值型数据,可行吗?
    • 可行,因为在KNN算法原理中,仅仅是计算特征值之间距离,目标数据没有参与运算

K折交叉验证

  • 目的:选出最为合适的模型超参数的取值,然后将超参数的值作用到模型的创建中
  • 思想:将样本的训练数据交叉的拆分出不同的训练集和验证集,使用交叉拆分出不同的训练集和验证集,分别测试模型的精准度,然后求出模型精准度的均值就是此次交叉验证的结果。将交叉验证作用到不同的超参数中,选出精准度最高的超参数作为模型创建的超参数即可
  • 实现思路:
    • 将数据集平均划分成k个等份
    • 使用1份数据作为测试数据,其余作为训练数据
    • 计算测试准确率
    • 使用不同的测试集,重复2,3步骤
    • 对准确率做平均,作为对未知数据预测准确率的估计
    • API
      • from sklearn.model_selection import cross_val_score
      • cross_val_score(estimator,X,y,cv)
        • estimator:模型对象
        • X,y:训练集数据
        • cv:折数
    • 交叉验证在knn中的使用
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import sklearn.datasets as datasets

knn = KNeighborsClassifier(n_neighbors=12)
iris = datasets.load_iris()
feature = iris['data']
target = iris['target']
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
cross_val_score(knn, x_train, y_train, cv=5).mean()

# 使用交叉验证和学习曲线寻找最优超参数

scores = []
ks = []
for k in range(3, 20):
     knn = KNeighborsClassifier(n_neighbors=k)
     score = cross_val_score(knn, x_train, y_train, cv=6).mean()
     scores.append(score)
     ks.append(k)
plt.plot(ks, scores)
plt.xlabel('k_value')
plt.ylabel('score')
plt.show()
ks_arr = np.array(ks)
score_arr = np.array(scores)
print(score_arr.max())
print(score_arr.argmax())
print(ks_arr[score_arr.argmax()])


  • 交叉验证也可以帮我们进行模型选择,以下是一组例子,分别使用KNN,logistic回归模型进行模型的选择和比较
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
import sklearn.datasets as datasets

iris = datasets.load_iris()
feature = iris['data']
target = iris['target']
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
knn = KNeighborsClassifier(n_neighbors=12)
print(cross_val_score(knn, x_train, y_train, cv=5).mean())
lr = LogisticRegression()
print(cross_val_score(lr, x_train, y_train, cv=5).mean())

  • K-Fold&cross_val_score
    • Scikit提供了K-Fold的API
      • n-split就是折数
      • shuffle就是对数据是否进行洗牌
      • random_state就是随机种子,固定随机性
from numpy import array
from sklearn.model_selection import KFold

data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6])
kFold = KFold(n_splits=3, shuffle=True, random_state=1)
for train, test in kFold.split(data):
    print('train:%s,test:%s' % (data[train], data[test]))
  • Scitkit中提取K-Fold接口的交叉验证接口sklearn.model_selection.cross_validate,但是该接口没有shuffle功能,所以结合K-Fold一起使用。如果train数据在分组前已经经过shuffle处理,比如使用train_test_split分组,那么可以直接使用cross_val_score接口
from sklearn.neighbors import KNeighborsClassifier
import sklearn.datasets as datasets
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score

iris = datasets.load_iris()
X, y = iris.data, iris.target
knn = KNeighborsClassifier(n_neighbors=12)
n_folds = 5
kFold = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(X)
score = cross_val_score(knn, X, y, cv=kFold)
print(score.mean())

线性回归+回归算法的评价指标

  • 回归问题的判定
    • 目标值是连续型的值,而分类问题的目标值是离散型的值
  • 回归处理的问题为预测
    • 预测房价
    • 销售额的预测
    • 设定贷款额度
    • 总结:上述案例,可以根据事物的相关特征预测出对应的结果值
  • 线性回归在生活中的映射:生活案例[预测学生的期末成绩]:
    • 期末成绩的制定:0.7考试成绩+0.3平时成绩,特征值为考试成绩和平时成绩,目标值为总成绩。从此案例中可以感受到
      • 回归算法预测出来的结果就是经过相关算法计算出来的结果值
      • 每个特征需要一个权重的占比,这个权重的占比确定后,则可以得到最终的计算结果,也就是获取了最终预测结果
import numpy as np
import pandas
from pandas import DataFrame
import matplotlib.pylab as plt
from pylab import mpl

dic = {
    '面积': [55, 76, 80, 100, 120, 150],
    '售价': [110, 152, 160, 200, 240, 300]
}
df = DataFrame(data=dic)
print(df)
mpl.rcParams['font.sans-serif'] = ['FangSong']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号‘-’显示为方块的问题
plt.scatter(df['面积'], df['售价'])
plt.xlabel('面积')
plt.ylabel('售价')
plt.title('面积和价钱的分布图')
plt.scatter(np.linspace(0, 180, num=100), np.linspace(0, 180, num=100)*2, alpha=0.3)
plt.show()

  • 思考:上述的线性方程y=wx+b其中x为特征y为目标,这种方程作为线性关系模型的预测数据的话是否可以满足所有的预测场景呢?

    • 如果现在房价受影响的不光是面积了,加入了采光率和楼层,那意味着特征变成了三种。在原始的线性方程y=wx+b中只可以有一个特征,则该方程不具有通用性。
    • 标准线性关系模型为:
      • 售价=(w1面积+w2采光率+w3楼层)+b==》 y=(w1x1+w2x2+···+wn*xn)+b
        • w又叫做权重。
        • b可以变换成w0*x0,x0=1
          • y=w0x0+w1x1+w2x2+···+wnxn
        • 权重向量(行向量):w0,w1,w2···wn
          • 行向量的转置就是列向量。行向量是一个n*1的矩阵,即矩阵由一个含n个元素的行所组成
  • 线性回归:

    • 找出特征和特征权重之间的一种组合,从而来预测对应的结果!!!
      • 线性方程式:
        • y=w1x1+w2x2+···+wn*xn+b
        • 为了方便后续写出矩阵的形式,我们这边可以稍作修改,令w0=b,x0=1,就可以写出下边的形式:
        • y=w0x0+w1x1+w2x2+···+wnxn
        • 假设现在有m个样本,写出矩阵的形式就是:
        • X = [ 1 x 1 1 x 1 2 ⋅ ⋅ ⋅ x 1 n 1 x 2 1 x 2 2 ⋅ ⋅ ⋅ x 2 n ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1 x m 1 x m 2 ⋅ ⋅ ⋅ x m n ] X=\left[ \begin{array}{lcr} 1& x_1^1 & x_1^2&···&x_1^n \\ 1& x_2^1 & x_2^2&···&x_2^n \\···& ··· & ···&···&···\\1& x_m^1 & x_m^2&···&x_m^n\end{array} \right] X=⎣⎢⎢⎡​11⋅⋅⋅1​x11​x21​⋅⋅⋅xm1​​x12​x22​⋅⋅⋅xm2​​⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅​x1n​x2n​⋅⋅⋅xmn​​⎦⎥⎥⎤​ Y = [ y 1 y 2 y 3 ⋅ ⋅ ⋅ y m ] Y=\left[ \begin{array}{lcr} y_1\\y_2\\y_3\\···\\y_m \end{array} \right] Y=⎣⎢⎢⎢⎢⎡​y1​y2​y3​⋅⋅⋅ym​​⎦⎥⎥⎥⎥⎤​
        • 权重w也可以写成矩阵的形式:
          • W = [ w 0 w 1 w 2 ⋅ ⋅ ⋅ w n ] W=\left[ \begin{array}{lcr} w_0&w_1&w_2&···&w_n\end{array} \right] W=[w0​​w1​​w2​​⋅⋅⋅​wn​​]
          • 那么可以写成一种简单明了的方式:
            • Y = X W T Y=XW^T Y=XWT
            • PS:n代表特征数目,m代表样本数目
  • 问题:真实结果和预测结果是否存在误差?

    • 如果房价预测案例中,特征与目标之间的分布规律不是线性的,那么还可以使用一条直线表示特征与目标之间的趋势呢?
      • 可以,只要保证直线距离所有的散点距离最近,则该直线还是可以在一定程度上表示非线性分布散点之间的分布规律,但是该规律存在误差
    • 误差存在,那么我们应该如何处理误差呢?在处理误差之前,我们必须先要知道一个回归算法的特性
      • 回归算法是一个迭代算法。
        • 当开始训练线性回归模型的时候,是逐步将样本数据带入模型对其进行训练的
        • 训练开始前先用部分样本数据训练模型生成一组w和b,对应的直线和数据对应散点的误差较大,通过不断的带入样本数据会逐步迭代更好的w和b从而使w和b的值更加的精准
        • 如何不断迭代的减少误差呢?
          • 通过损失函数来表示误差
            • 总损失定义:
              • J ( θ ) = ( h w ( x 1 ) − y 1 ) 2 + ( h w ( x 2 ) − y 2 ) 2 + ⋅ ⋅ ⋅ + ( h w ( x m ) − y m ) 2 = ∑ i = 1 m ( h w ( x i ) − y i ) 2 J(θ)=(h_w(x_1)-y_1)^2+(h_w(x_2)-y_2)^2+···+(h_w(x_m)-y_m)^2=\sum_{i=1}^m(h_w(x_i)-y_i)^2 J(θ)=(hw​(x1​)−y1​)2+(hw​(x2​)−y2​)2+⋅⋅⋅+(hw​(xm​)−ym​)2=∑i=1m​(hw​(xi​)−yi​)2
              • y i y_i yi​:第i个训练样本的真实值
              • h w ( x i ) h_w(x_i) hw​(xi​):预测值
          • 损失函数也可以表示为:
            • ∑ i = 1 m ( y i − y i ^ ) 2 = ∑ i = 1 m ( y i − x i w T ) 2 \sum\limits_{i=1}^m(y_i-\hat{y_i})^2=\sum\limits_{i=1}^m(y_i-x_iw^T)^2 i=1∑m​(yi​−yi​^​)2=i=1∑m​(yi​−xi​wT)2
        • 因此得知误差的大小线性回归方程中的系数w是有直接的关系
          • w(权重)的不同会导致误差大小的不同
          • 那么最终的问题就转换成了,【如何去求解方程中的w使得误差最小】
  • L2范式

    • 这个损失函数代表了向量yi-y^i的L2范式的平方结果,L2范式的本质就是欧氏距离,即是两个向量上的每个点对应相减后的平方和再开平方,我们现在只实现向量上每个点对应相减后的平方和,并没有开方,所以我们的损失函数是L2范式,即欧氏距离的平方结果。
    • d i s t = ∑ i = 1 n ( x i − y i ) 2 dist=\sqrt{\sum\limits_{i=1}^n}(x_i-y_i)^2 dist=i=1∑n​ ​(xi​−yi​)2 = m i n w ∣ ∣ y − x w T ∣ ∣ 2 min_w||y-xw^T||_2 minw​∣∣y−xwT∣∣2​
    • 在这个平方结果下,我们的y和y^分别是我们的真实值和预测值,也就是说,这个损失函数实际计算我们的真实标签和预测值之间的距离。因此,我们认为这个损失函数衡量了我们构造的模型的预测结果和真实标签的差异,因此我们固然希望我们的预测结果和真实值差异越小越好,所以我们的求解目标就可以转换为:
    • m i n w ∣ ∣ y − x w T ∣ ∣ 2 2 min_w||y-xw^T||_2 {^2} minw​∣∣y−xwT∣∣2​2
    • SSE&RSS:
      • 其中右下角的2表示向量y-xw的L2范式,也就是我们损失函数所代表的意义。在L2范式上开平方就是我们的损失函数。我们往往称呼这个式子为SSE(Sun of Sqaured Error,误差平方和)或者RSS(Residual Sum of Squares,残差平方和)
    • 最小二乘法
      • 现在问题转换成了求解让RSS的最小化参数向量w,这种通过最小化真实值和预测值之间的RSS来求解参数的方法叫做最小二乘法
      • 求解极值(最小值)的第一步求导一阶导数并让一阶导数等于0
      • 首先w表示的是一个列向量(矩阵),我们现在对列向量求导
      • 首先将L2范式拆开:
      • ∂ R S S ∂ w = ∂ ∣ ∣ y − x w ∣ ∣ 2 2 ∂ w = ∂ ( y − x w ) T ( y − x w ) ∂ w \frac{\partial RSS}{\partial w}=\frac{\partial||y-xw||_2 {^2}}{\partial w}=\frac{\partial(y-xw)^T(y-xw)}{\partial w} ∂w∂RSS​=∂w∂∣∣y−xw∣∣2​2​=∂w∂(y−xw)T(y−xw)​
      • 两个向量(y&xw)的平方就等于两个向量的转置乘以两个向量本身
      • 处理转置乘法和除法:
      • ( A − B ) T = A T − B T 并 且 ( A B ) T = B T ∗ A T (A-B)^T=A^T-B^T并且(AB)^T=B^T*A^T (A−B)T=AT−BT并且(AB)T=BT∗AT
      • = ∂ ( y T − w T x T ) ( y − x w ) ∂ w =\frac{\partial(y^T-w^Tx^T)(y-xw)}{\partial w} =∂w∂(yT−wTxT)(y−xw)​
      • 然后将上面的分子进行多项式相乘
      • = ∂ ( y T y − w T x T y − y T x w + w T x T x w ) ∂ w = ∂ y T y − ∂ w T x T y − ∂ y T x w + ∂ w T x T x w ∂ w =\frac{\partial (y^Ty-w^Tx^Ty-y^Txw+w^Tx^Txw)}{\partial w}= \frac{\partial y^Ty-\partial w^Tx^Ty-\partial y^Txw+\partial w^Tx^Txw}{\partial w} =∂w∂(yTy−wTxTy−yTxw+wTxTxw)​=∂w∂yTy−∂wTxTy−∂yTxw+∂wTxTxw​
      • 在矩阵求导中如果小a为常数项,A为矩阵则:
      • ∂ a ∂ A = 0 , ∂ A T B T C ∂ A = B T C , ∂ C T B A ∂ A = B T C , ∂ A T B A ∂ A = ( B + B T ) A \frac{\partial a}{\partial A}=0 , \frac{\partial A^TB^TC}{\partial A}=B^TC,\frac{\partial C^TBA}{\partial A}=B^TC,\frac{\partial A^TBA}{\partial A}=(B+B^T)A ∂A∂a​=0,∂A∂ATBTC​=BTC,∂A∂CTBA​=BTC,∂A∂ATBA​=(B+BT)A
      • 分子上的每一项对w进行求导的结果是:
      • = 0 − x T y − x T y + 2 x T x w = x T x w − x T y =0-x^Ty-x^Ty+2x^Txw=x^Txw-x^Ty =0−xTy−xTy+2xTxw=xTxw−xTy
      • 至此我们就求解出对w求导的一阶导数,接下来让一阶导数,接下来让一阶导数为0则就求出了最小误差下的w的值了。
      • x T x w − x T y = 0 x^Txw-x^Ty=0 xTxw−xTy=0
      • x T x w = x T y x^Txw=x^Ty xTxw=xTy
      • 左乘一个 ( x T x ) − 1 (x^Tx)^{-1} (xTx)−1则有:
      • w = ( x T x ) − 1 x T y w=(x^Tx)^{-1}x^Ty w=(xTx)−1xTy
      • A − 1 ∗ A = 1 A^{-1}*A=1 A−1∗A=1
    • API
      • 最小二乘(正规方程):from sklearn.linear_model import LinearRegression
      • fit_intercept:布尔值,可不填,默认为True,是否计算模型的截距。如果设置为False,则不会计算截距。
      • normalize:布尔值,可不填,默认为False,当fit_intercept为False,此参数可忽略。如果为True,则特征矩阵X进入回归之前将会被减去均值(中心化)并除以L2范式(缩放)。如果你希望进行标准化,请在fit数据之前使用preprocessing模块中的标准化专用类StandardScaler
      • copy_X:布尔值,可不填,默认为True。如果为真,将在X.copy()上进行操作否则的话,原本的特征矩阵X可能被线性回归影响并覆盖
      • n_jobs:整数或者None,可不填,默认为None。用于计算的作业数。只在多标签的回归和数据量足够大的时候才生效。除非None在joblib.parallel_backend上下文,否则None统一表示为1。如果输入-1,则表示使用全部的cpu来进行计算
      • 这些参数并没有一个是必填的,更没有对我们的模型有不可替代的参数,这说明,线性回归的性能,往往取决于数据本身,而并非是我们的调参能力,线性回归也因此对数据有着很高的要求。幸运的是,大部分连续型变量之间,存在着或多或少的线性联系。所以线性回归固然简单,却很强大。sklearn的线性回归可以处理多标签问题,只需在fit的时候输入多维度标签就可以了。
      • normalize参数:如果为True,则会对特征数据进行归一化处理,如果想对特征数据进行标准化处理,则需要训练模型前调用相关工具类对其进行标准化处理。
      • 使用最小二乘法对房屋进行预测
      • 特征介绍:
        • AveBedrms:该街区平均的卧室数目
        • Population:街区人口
        • AveOccup:平均入住率
        • Latitude:街区的纬度
        • Longitude:街区的经度
        • MedInc:街区住户收入的中位数
        • HouseAge:房屋使用年数中位数
        • AveRooms:街区平均房屋的数量
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing as fch

# print(fch())
feature = fch().data
target = fch().target
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.1, random_state=2021)
liner = LinearRegression()
liner.fit(x_train, y_train)
liner.coef_  # 返回的是w系数
# print(liner.coef_)
liner.intercept_  # 返回的是截距
# print(liner.intercept_)
# 将系数和特征名称结合在一起查看
[*zip(fch().feature_names, liner.coef_)]

回归模型的评价指标

  • 回归类算法的模型评估一直都是回归算法中的一个难点,回归类与分类型算法的模型评估其实是相似的法则- -找真实标签和预测值的差异。只不过在分类型算法,这个差异只有一种角度来评判,那就是是否预测到了正确的分类,而在我们的回归类算法,我们有两种不同的角度来看待回归的效果:
    • 第一:我们是否预测到了正确或者接近正确的数值(因为误差的存在)
    • 第二:我们是否拟合到了足够的信息。(是否模型预测的结果线性和样本真实的结果的线性更加吻合)
    • 这两种角度,分别对应着不同的模型评估指标
  • 是否预测到了正确的数值
    • 回忆下我们的残差平方和RSS,它的本质是我们的预测值和真实值之间的差异,也就是从一种角度来评估我们回归的效力,所以RSS既是我们的损失函数,也是我们回归类模型的模型评估指标之一。但是,RSS有着致命的缺点: 它是一个*的和,可以无限地大或者无限的小。我们只知道,我们想要求解最小的RSS,从RSS的公式来看,它不能为负,所以 RSS越接近0越好,但我们没有一个概念,究竟多小才算好,多接近0才算好?为了应对这种状况,sklearn中使用RSS 的变体,均方误差MSE(mean squared error)来衡量我们的预测值和真实值的差异:
    • M S E = 1 m ∑ i = 1 m ( y i − y i ^ ) 2 MSE=\frac{1}{m}\sum\limits_{i=1}^m (y_i-\hat{y_i})^2 MSE=m1​i=1∑m​(yi​−yi​^​)2
    • 均方误差,本质是在RSS的基础上除以了样本总量,得到了每个样本量上的平均误差。有了平均误差,我们就可以将平均误差和我们的标签的取值范围(最大值和最小值)在一起比较,以此获得一个较为可靠的评估依据。(查看这个错误有多严重)
      • 因为标签的最大值和最小值可以表示标签的一个分部情况,那么将其最大值和最小值和平均误差比较就可以大概看出在每个样本上的误差或者错误有多严重。
      • 在sklearn当中,我们有两种方式调用这个评估指标:
        • 一种是使用sklearn专用的模型评估模块metrics里的类mean_squared_error
        • 另一种是调用交叉验证的类cross_val_score并使用里面的scoring参数来设置为:neg_mean_squared_error使用均方误差。
        • 交叉验证求得的均方误差为负值
          • 均方误差的计算公式中求得的均方误差的值不可能为负。但是sklearn中的参数scoring下,均方误差作为评判 标准时,却是计算负均方误差(neg_mean_squared_error)。这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均方误差本身是一种误差,所以被sklearn划分为模型的一种损失(loss)。在sklearn当中,所有的损失都使用负数表示,因此均方误差也被显示为负数了。真正的均方误差MSE的数值,其实就是neg_mean_squared_error去掉负号的数字。
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing as fch

# print(fch())
feature = fch().data
target = fch().target
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.1, random_state=2021)
liner = LinearRegression()
liner.fit(x_train, y_train)
liner.coef_  # 返回的是w系数
# print(liner.coef_)
liner.intercept_  # 返回的是截距
# print(liner.intercept_)
# 将系数和特征名称结合在一起查看
[*zip(fch().feature_names, liner.coef_)]
# print(liner.score(x_test, y_test))
from sklearn.metrics import mean_squared_error

y_true = y_test
y_pred = liner.predict(x_test)
mean_squared_error(y_true, y_pred)
# print(y_true.max())
# print(y_true.min())

from sklearn.model_selection import cross_val_score

print(cross_val_score(liner, x_train, y_train, cv=5, scoring='neg_mean_squared_error').mean())
  • 绝对误差
    • 除了MSE,我们还有与MSE类似的MAE(Mean absolute error,绝对均值误差):
    • M A E = 1 m ∑ i = 0 m − 1 ∣ y i − y i ^ ∣ MAE=\frac{1}{m}\sum\limits_{i=0}^{m-1}|y_i-\hat{y_i}| MAE=m1​i=0∑m−1​∣yi​−yi​^​∣
    • 其表达的概念与均方误差完全一致,不过在真实标签和预测值之间的差异我们使用的是L1范式(绝对值)。现实使用中,MSE和MAE选一个使用就可以了
    • 在sklearn当中,我们使用命令
      • from sklearn.metrics import mean_absolute_error
      • 同时,我们也可以用交叉验证中的scoring="neg_mean_absolute_error"
  • 是否拟合了足够的信息
    • 对于回归类算法,只探索数据预测是否准确是不足够的。除了数据本身的数值大小之外,我们还希望我们的模型能够捕捉到数据的”规律“,比如数据的分布规律(抛物线),单调性等等。而是否捕获到这些信息是无法使用MSE来衡量的。
      机器学习入门基础(一)
  • 看这张图,其中红色是我们的真实标签,而蓝色线是我们模型预测的值。这是一种比较极端的情况,但极有可能发生。这张图像上前半部分的拟合非常成功,看上去我们的真实标签和我们的预测结果几乎重合,但后半部分的拟合非常糟糕,模型向着与真实标签完全相反的方向去了。对于这样的一个拟合模型,如果我们使用MSE来对它进行判断,它的MSE会很小,因为大部分样本其实都被完美拟合了,少数样本的真实值与预测值的巨大差异在被均分到每个样本上之后,MSE就会很小。但这样的拟合结果不是一个好的结果,因为一旦我的新样本是处于拟合曲线的后半段的,我的预测结果必然会有巨大的偏差。所以,我们希望找到新的指标,除了判断预测的数值是否正确之外,还能够判断我们的模型是否拟合了足够多的,数值之外的信息。
  • 在我们学习降维选择,我们提到我们使用方差来衡量数据上的信息量。如果方差越大,代表数据上的信息量越多,而这个信息量(数据潜在的规律)不仅包括了数值的大小,还包括了我们希望模型捕捉的那些规律。为了衡量模型对数据上的信息量的捕捉,我们定义了 R 2 R^2 R2来帮助我们:
    R 2 = 1 − ∑ i = 0 m ( y i − y i ^ ) 2 ∑ i = 0 m ( y i − y ˉ ) 2 = 1 − R S S ∑ i = 0 m ( y i − y ˉ ) 2 R^2=1-\frac{\sum_{i=0}^m(y_i-\hat{y_i})^2}{\sum_{i=0}^m(y_i-\bar{y})^2}=1-\frac{RSS}{\sum_{i=0}^m(y_i-\bar{y})^2} R2=1−∑i=0m​(yi​−yˉ​)2∑i=0m​(yi​−yi​^​)2​=1−∑i=0m​(yi​−yˉ​)2RSS​
  • 其中,y是我们的真实标签, y ^ \hat{y} y^​是我们的预测结果, y ˉ \bar{y} yˉ​是我们的均值, y i − y ˉ y_i-\bar{y} yi​−yˉ​如果除以样本量m就是我们的方差。方差的本质是任意一个y值和样本均值的差异,差异越大,这些值所带的信息越多。在 R 2 R^2 R2中,分子是真实值和预测值之间的差值,也就是我们的模型没有捕获到的信息总量,分母是真实标签所带的信息量,所以其衡量的是1-我们的模型没有捕获到的信息量占真实标签中所带的信息量的比例,所以, R 2 R^2 R2越接近1越好。
  • 分母其实可以表示称为样本的潜在规律,分子为模型的误差(损失),那么样本数据潜在的规律是不变的,则误差越小则分子分母表达式返回的结果越小,则 R 2 越 接 近 1 R^2越接近1 R2越接近1
  • 可以用三方式来调用
    • 一种是直接从metrics中导入r2_score,输入预测值和真实值打分
    • 第二种是直接从线性回归LinerRegression的接口score来调用
    • 第三种是在交叉验证中,输入“r2”来调用
from sklearn.metrics import r2_score
from sklearn.model_selection import cross_val_score

print(r2_score(y_test, liner.predict(x_test)))
print(liner.score(x_test, y_test))
print(cross_val_score(liner, x_train, y_train, cv=5, scoring='r2').mean())
  • 绘制拟合图
import matplotlib.pyplot as plt

plt.plot(range(len(y_test)), sorted(y_test), c='black', label='y_true')
plt.plot(range(len(y_pred)), sorted(y_pred), c='red', label='y_pred')
plt.legend()
plt.show()


机器学习入门基础(一)

  • 可见,虽然我们的大部分数据被拟合得比较好,但是图像的开头和结尾处却又着较大的拟合误差。如果我们在图像右侧分布着更多的数据,我们的模型就会越来越偏离我们真正的标签。这种结果类似于我们前面提到的,虽然在有限的数据集上将数值预测正确了,但却没有正确拟合数据的分布,如果有更多的数据进入我们的模型,那数据标签被预测错误的可能性是非常大的。
  • 实战
    • 房地产估价数据集
      • 数据集信息
        • 房地产估值的市场历史数据集来自*新北市新店区。“房地产估价” 是一个回归问题。
      • 属性信息
      • 输入
        • X1 =交易日期(例如,2013.250 = 2013年3月,2013.500 = 2013年6月,等等)
        • X2 =房屋年龄(单位:年)
        • X3 =到最近的捷运站的距离(单位:米) )
        • X4 =步行生活圈中的便利店的数量(整数)
        • X5 =地理坐标,纬度。(单位:度)
        • X6 =地理坐标,经度。(单位:度)
      • 输出结果
        • Y =单位面积的房价(10000新台币/ Ping,其中Ping是本地单位,1 Ping = 3.3米平方)
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error as MSE
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
import sklearn.datasets as datasets

df = pd.read_excel('Real estate valuation data set.xlsx')
df.drop(labels='No', axis=1, inplace=True)
# print(df.head())
# print(df)
feature = df.loc[:, df.columns != 'Y house price of unit area']
target = df['Y house price of unit area']
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.2, random_state=2021)
linner = LinearRegression().fit(x_train, y_train)
# 模型在测试集的表现
y_true = y_test
y_pred = linner.predict(x_test)
print(MSE(y_true, y_pred))
print(y_true.max())
print(y_true.min())
print(r2_score(y_true, y_pred))
# 模型在训练集的表现
print(MSE(y_train, linner.predict(x_train)))
print(r2_score(y_train, linner.predict(x_train)))

  • 总结
    • 欠拟合:(对训练集的数据和测试集的数据拟合的都不是很好)
      原因:模型学习到样本的特征太少
      解决:增加样本的特征数量(多项式回归)
      多项式回归:from sklearn.preprocessing import PolynomialFeatures
      在原有特征的基础上增加高次方特征
    • 过拟合:(对训练集的数据高度拟合,对测试集的数据拟合的很离谱)
      原因:原始特征过多,存在一些嘈杂特征。
      解决:1.进行特征选择,消除关联性大的特征
      2.正则化之岭回归:from sklearn.linear_model import Ridge
      将对模型影响较大的特征(高次方)的权重系数变小,将模型弯曲程度大的地方捋直一定,降低关联性大的特征对预测模型的影响
  • 模型的保存和加载
    • 方式一 (推荐):from sklearn.externals import joblib
      joblib.dump(model,‘xxx.m’):保存
      joblib.load(‘xxx.m’):加载
    • 方式二:import pickle
      with open(’./123.pkl’,‘wb’) as fp:
      pickle.dump(linner,fp)
      with open(’./123.pkl’,‘rb’) as fp:
      linner = pickle.load(fp)
  • 欠拟合&&过拟合
    • 欠拟合:一个假设在训练数据上不能获得很好的拟合,但是在训练数据以外的数据集上也不能很好的拟合数据,此时认为这个假设出现了欠拟合的现象。(模型过于简单)
    • 过拟合:一个假设在训练数据上能够获得比其他假设更好的拟合,但是在训练数据以外的数据集上却不能很好的拟合数据,此时认为这个假设出现了过拟合现象。(模型过于复杂)
      机器学习入门基础(一)
  • 欠拟合和过拟合问题的解决
    • 欠拟合:
      • 原因:模型学习到样本的特征太少
      • 解决:增加样本的特征数量(多项式回归)
    • 过拟合:
      • 原因:原始特征过多,存在一些嘈杂特征。
      • 解决:
        • 进行特征选择,消除关联大的特征(很难做)
        • 正则化之岭回归
    • 模型的复杂度:回归出直线or曲线
      • 我们的回归模型最终回归出的一定是直线吗(y=wx+b)?有没有可能是曲线(非线性)呢(y=wx^2+b)?
        • 我们都知道回归模型算法就是在寻找特征值和目标值之间存在的某种关系,那么这种关系越复杂则表示训练出的模型的复杂度越高,反之越低。
        • 模型的复杂度是由特征和目标之间的关系导致的!特征和目标之间的关系不仅仅是线性关系!
    • 欠拟合的处理:多项式回归
      • 为了解决欠拟合的情况,经常需要提高线性的次数(高次多项式)建立模型拟合曲线,次数过多会导致过拟合,次数不够会欠拟合
        • y=w*x+b一次多项式函数
        • y=w1 * x^2+w2 * x+b 二次多项式函数
        • y=w1 * x^3 +w2 * x^2+w3 * x+b 三次多项式函数
        • ……
        • 高次多项式函数表示为曲线
    • 相对于线性回归模型y=wx+b只能解决线性(回归出的为直线)问题,多项式回归能够解决非线性回归(回归出的为曲线)问题。
    • 拿最简单的线性模型来说,其数学表达式可以表示为:y=wx+b,它表示的是一条直线,而多项式回归则可以表示成:y=w1 * x^2+w2 * x+b,它表示的是二次曲线,实际上,多项式回归可以看成特殊的线性模型,即把x∧2看成一个特征,把x看成另一个特征,这样就可以表示成y=w1z+w2x+b,其中z=x∧2,这样多项式回归实际上就变成线性回归了。
    • 当然还可以将y=wx+b转为更高次的多项式。是否需要转成更高次的多项式取决于我们想要拟合样本的程度了,更高次的多项式可以更好的拟合我们的样本数据,但是也不是一定的,很可能会造成过拟合。
    • 示例:根据蛋糕大小预测价格
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt

# 样本训练数据,特征,目标
x_train = [[6], [8], [10], [16], [18]]  # 大小
y_train = [[7], [9], [15], [17.5], [18]]  # 价格
# 一次线性回归的学习和预测y=wx+b
re = LinearRegression()
re.fit(x_train, y_train)
# 画出一次线性回归的拟合曲线
xx = np.linspace(0, 25, 100)
xx = xx.reshape(-1, 1)
yy = re.predict(xx)
plt.scatter(x_train, y_train)  # 原始样本数据的分布规律
plt.plot(xx, yy)
plt.show()

  • 建立二次多项式线性回归模型进行预测
    • 根据二次多项式可知,需要给原始特征添加更高次特征数据x^2
    • 如何给样本添加高次的特征数据?
      • 使用sklearn.preprocessing import PolynomialFeatures来进行更高次特征的构造
        • 它是使用多项式的方法来构造的。如果有a,b两个特征,那么它的2次多项式为(1,a,b,a^2 ,ab,b^2)
        • PolynomialFeatures有三个参数:
          • degree:控制多项式的度
          • interaction_only:默认为False,如果指定为True,那么就不会有特征和特征自己结合的项,上面的二次项没有a^2, b^2
          • include_bias:默认为True。如果为False的话,那么就不会有上面的1那一项
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt

# 样本训练数据,特征,目标
x_train = [[6], [8], [10], [16], [18]]  # 大小
y_train = [[7], [9], [15], [17.5], [18]]  # 价格
# 一次线性回归的学习和预测y=wx+b
re = LinearRegression()
re.fit(x_train, y_train)
# 画出一次线性回归的拟合曲线
xx = np.linspace(0, 25, 100)
xx = xx.reshape(-1, 1)
yy = re.predict(xx)
plt.scatter(x_train, y_train)  # 原始样本数据的分布规律
plt.plot(xx, yy)
plt.show()
from sklearn.preprocessing import PolynomialFeatures

# 参数degree控制增加特征的次数
# 参数interaction_only默认为False是有二次项,如果变成True就会去掉二次项
# 参数include_bias默认为True,如果是False就是不要增加出来的1那一项
c = [[5, 10]]
pl = PolynomialFeatures()
b = pl.fit_transform(c)
print(b)
# 建立二次多项式回归模型进行预测
poly2 = PolynomialFeatures(degree=2)  # 2次多项式特征生成器
x_train_poly2 = poly2.fit_transform(x_train)
# 建立模型预测
liner_poly2 = LinearRegression()
liner_poly2.fit(x_train_poly2, y_train)
# 画二次多项式回归的图
xx_poly2 = poly2.transform(xx)
yy_poly2 = liner_poly2.predict(xx_poly2)
plt.scatter(x_train, y_train)
plt.plot(xx, yy, label='Degree1')
plt.plot(xx, yy_poly2, label='Degree2')
plt.legend()
plt.show()
poly3 = PolynomialFeatures(degree=4)
x_train_poly3 = poly3.fit_transform(x_train)
liner_poly3 = LinearRegression()
liner_poly3.fit(x_train_poly3, y_train)
xx_poly3 = poly3.transform(xx)
yy_poly3 = liner_poly3.predict(xx_poly3)
plt.scatter(x_train, y_train)
plt.plot(xx, yy, label='Degree1')
plt.plot(xx, yy_poly3, label='Degree2')
plt.legend()
plt.show()
  • 过拟合处理:正则化
    • 将过拟合的曲线的凹凸幅度减少就可以将过拟合曲线趋近于拟合曲线了。那么过拟合曲线的凹凸肯定是由y=wx2+x3+x4中的高次项导致的**
    • 那么L2正则化就是通过将高次项的特征的权重w调小到趋近于0,则高次项的特征就几乎没有了,那么凹凸幅度就会减少,就越趋近于拟合曲线了!
    • LinnerRegression是没有办法进行正则化的,所以该算法模型容易出现过拟合,并且无法解决。
    • L2正则化:使用带有正则化算法的回归模型(Ridge岭回归)处理过拟合的问题。
  • Ridge岭回归:具备L2正则化的线性回归模型
    • API:from sklearn.linear_model import Ridge
    • Ridge(alpha=1.0):
      • alpha:正则化的力度,力度越大,则表示高次项的权重w越接近于0,导致过拟合曲线的凹凸幅度越小。
        取值:0-1小数或者1-10整数
      • coef_:回归系数
    • 使用岭回归可以通过控制正则化力度参数alpha降低高次项特征的权重
from sklearn.linear_model import Ridge
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures

# 样本的训练数据,特征和目标值
x_train = [[6], [8], [10], [14], [18]] #大小
y_train = [[7], [9], [13], [17.5], [18]]#价格

# 在原有特征上增加3次方特征
p = PolynomialFeatures(degree=3)
d_3_train = p.fit_transform(x_train)
linear = LinearRegression().fit(d_3_train,y_train)
# 原本线性回归权重系数
linear.coef_

array([[ 0.        , -1.42626096,  0.31320489, -0.01103344]])

# 使用L2正则化力度调整权重系数
# 参数alpha正则化力度,可以通过学习曲线寻找最优alpha值
ridge = Ridge(alpha=0.5)
ridge.fit(d_3_train,y_train)
ridge.coef_
# 调整后权重系数,明显将高权重的变低了
array([[ 0.        , -0.14579637,  0.19991159, -0.00792083]])
  • 岭回归的优点:
    • 获取的回归系数更符合实际更可靠
    • 在病态数据(异常值多的数据)偏多的研究中有更大的存在意义
  • 模型的保存和加载
    • 方式一 (推荐使用方式一,更加便捷)
      • from sklearn.externals import joblib
        joblib.dump(model,‘xxx.m’):保存
        joblib.load(‘xxx.m’):加载
    • 方式二
      • import pickle
        with open(’./123.pkl’,‘wb’) as fp:
        pickle.dump(linner,fp)
        with open(’./123.pkl’,‘rb’) as fp:
        linner = pickle.load(fp)

朴素贝叶斯算法

  • 在许多分类算法应用中,特征和标签之间的关系并非是决定性的。比如说,我们想预测一个人究竟是否会在泰坦尼克号海难中生存下来,那我们可以建立某个分类模型来学习我们的训练集。在训练中,其中一个人的特征为:30岁,男,普 通舱,他最后在泰坦尼克号海难中去世了。当我们测试的时候,我们发现有另一个人的特征也为:30岁,男,普通 舱。基于在训练集中的学习,我们的模型必然会给这个人打上标签:去世。然而这个人的真实情况一定是去世了吗?并非如此。也许这个人是心脏病患者,得到了上救生艇的优先权。又有可能,这个人就是挤上了救生艇,活了下来。对分类算法 来说,基于训练的经验,这个人“很有可能”是没有活下来,但算法永远也无法确定”这个人一定没有活下来“。即便这 个人最后真的没有活下来,算法也无法确定基于训练数据给出的判断,是否真的解释了这个人没有存活下来的真实情况。
  • 这就是说,算法得出的结论,永远不是100%确定的,更多的是判断出了一种“样本的标签更可能是某类的可能性”,而非一种“确定”。我们通过模型算法的某些规定,来强行让算法为我们返回一个固定的分类结果。但许多时候,我们也希望能够理解算法判断出结果的可能性概率。
  • 无论如何,我们都希望使用真正的概率来衡量可能性,因此就有了真正的概率算法:朴素贝叶斯。
  • 朴素贝叶斯是一种直接衡量标签和特征之间的概率关系的有监督学习算法,是一种专分类的算法。朴素贝叶斯的算法根源是基于概率论与数理统计的贝叶斯理论。
  • 概率计算准则:联合概率和条件概率
    • 联合概率:包含多个条件,且所有条件同时成立的概率
      • 记作P(A,B)
      • P(A,B)=P(A)P(B)
    • 条件概率:就是事件A在另外一个事件B已经发生条件下的概率
      • 记作P(A|B)
      • 特性:P(A1,A2|B)=P(A1|B)P(A2|B)
      • 注意:此条件概率的成立,是由于A1,A2相互独立的结果

机器学习入门基础(一)

  • -女神喜欢一个人的概率:4/7
    -职业是程序员并且体型匀称的概率:3/74/7=12/49
    -在女神喜欢的条件下,职业是程序员的概率:2/4=1/2
    -在女神喜欢的条件下,职业是产品,体重超重的概率:2/4
    1/4=1/8
  • 注意:
    • 上述的求概率公式只适用于各个特征之间是条件独立(每个特征之间没有必然关系)的。条件不独立指的是特征之间有关联的比如,体重和是否喜欢吃零食这两个条件之间就有关联。
    • 朴素贝叶斯只适用于特征之间是条件独立的情况下。否则分类效果不好。这里的朴素指的就是条件独立
    • 朴素贝叶斯主要被广泛的适用于文档分类中!
  • 朴素贝叶斯的分类
    • 在sk-learn中提供了三种不同类型的贝叶斯模型算法
      • 高斯模型
      • 多项式模型
      • 伯努利模型
    • 高斯模型
      • 介绍
        • **大家在学习高等数学时,应该学过高斯分布,也就是正态分布,是一种连续型变量的概率分布。简单来说,高斯分布就是当频率直方图的区间变得特别小时的拟合曲线,像座小山峰,其中两端的特别小,越往中间越高。
          **
        • 所谓正态分布,就是正常形态的分布,它是自然界的一种规律。现实生活中有很多现象均服从高斯分布,比如收入,身高,体重等,大部分都处于中等水平,特别少和特别多的比例都会比较低。
      • 高斯分布(正态分布)
        • 在数学中往往正态分布被称为高斯分布
        • 通过假设P(xi|Y)是服从高斯分布(也就是正态分布),来估计训练集数据的每个特征分到每个类别Y的条件概率P是多少(估计每个特征下对应每个类别的条件概率)。对于每个特征下的对应每个分类结果概率的取值,高斯朴素贝叶斯有如下公式:
        • exp函数为高等数学里以自然常数e为底的指数函数
        • P ( x i ∣ Y ) = f ( x i ; μ y , σ y ) ∗ ϵ = 1 2 π σ y 2 e x p ( − ( x i − μ y ) 2 2 σ y 2 ) P(x_i|Y)=f(x_i;\mu_y,σ_y)*\epsilon=\frac{1}{\sqrt{2\piσ_y^2}}exp(-\frac{(x_i-\mu_y)^2}{2σ_y^2}) P(xi​∣Y)=f(xi​;μy​,σy​)∗ϵ=2πσy2​ ​1​exp(−2σy2​(xi​−μy​)2​)
          ∘ \circ ∘ Y:分类的类别
          ∘ \circ ∘ x:分类的特征
          ∘ \circ ∘ 特征所属标签的均值(
上一篇:机器学习sklearn(60):算法实例(十七)分类(十)逻辑回归(五)附录


下一篇:机器学习sklearn(二):SKLEARN快速开始