跳转至

机器学习

📖 阅读信息

阅读时间:14 分钟 | 中文字符:5503 | 有效代码行数:412

人工智能概述

机器学习与人工智能、深度学习

三者之间是包含与被包含的关系

  • 人工智能:最大的概念
    最开始的时候是为了实现自动的下棋,那个时候就是人工智能了
    在 1958 年,有最开始的人工智能的会议。
  • 机器学习:实际上这个东西在上个世纪八十年代上就得到了广泛的应用
  • 深度学习:在图像识别中取得了不错的效果
    • 应用在挖掘数据
    • 应用在图像的识别
    • 应用在自然语言的处理——翻译,还有很多的聊天的人工智能

什么是机器学习

定义

机器学习是从数据中自动分析获得模型,并利用模型对未知的数据进行预测

解释

利用以往的规律进行学习

例子

比如使用人工智能识别猫和狗的照片,就是使用大量的图片进行训练得到的

还有房屋价格的预测等等

但是这些历史数据应该是怎么样的?

数据集的组成

  • 结构:特征值+目标值

对于每一行数据我们可以称之为样本

有些数据集可以没有目标值

机器学习算法分类

要使得机器有着识别猫和狗的能力,应该从机器中进行学习
我们需要的也是特征值和目标值
这里的目标值就是猫?还是狗


所以这里的目标值是类别,属于分类问题
但是对于房屋价格的预测,最后的目标值是一种连续型的数据,属于回归问题
当我们遇到的数据集中没有目标值时,称为无监督学习

  • 监督学习
    • 分类问题
    • 回归问题
  • 无监督学习

例子

预测气温是多少度,是回归问题

预测明天的天气,是分类问题

人脸的年龄预测:看怎么定义,可以是回归/分类

人脸的识别:分类

机器学习算法的分类

  • 监督学习:
    • 分类:K-近邻、贝叶斯、决策树与随机森林、逻辑回归
    • 回归:线性回归,岭回归
  • 无监督学习
    • 聚类 k-means

机器学习的开发流程

流程

  1. 获取数据
  2. 数据处理
  3. 特征工程
  4. 机器学习算法训练-模型
  5. 模型评估

学习框架和资料介绍

重点的问题:

  1. 算法是核心,数据和计算是基础
  2. 找准定位
    大部分复杂模型的算法设计都是算法工程师在做,实战类的书籍

书籍:
- 机器学习-周志华 - 统计学习方法-李航 - 深度学习-"花书"

常见的深度学习的框架

一般是 pytorch 和 TF 使用的多一点

特征工程

数据集

可用数据集

公司内部:百度之类的
数据接口:花钱
数据集


所以在学习阶段我们会用到哪些数据集?
1. Sklearn 2. Kaggle 3. Ucl
我们现在主要介绍一下 sklearn
- Python 语言的机器学习工具 - 包括很多的知名的机器学习算法的实现 - 易于上手 - 安装 pip install Scikit-learn (在 cmd 中运行安装)(使用的是 pycharm 的话在里面的终端安装即可) - 安装好之后直接在 python 中好像可以直接使用
如下的代码块

Python
# 1. 导入数据集模块
from sklearn import datasets

# 2. 加载经典数据集(以鸢尾花数据集为例)
iris = datasets.load_iris()  # 这是一个内置的小数据集,无需下载

# 3. 查看数据集内容
print("特征数据(前5行):\n", iris.data[:5])  # 数据集的特征(输入变量)
print("\n标签数据:\n", iris.target)  # 数据集的标签(输出变量/分类结果)
print("\n特征名称:\n", iris.feature_names)  # 每个特征的名称
print("\n标签名称:\n", iris.target_names)  # 每个标签对应的类别名称
print("\n数据集描述:\n", iris.DESCR)  # 数据集的详细说明

介绍

他的文档是非常完善的

可以直接在文档中进行相关的学习

网址

如何使用这个数据集

API 介绍

  • sklearn. datasets
    • 加载获取流行数据集
    • datasets. load_*()
      • 获取小规模的数据集
    • datasets. fetch_*(data_home=None)
      • 获取大量的数据集,需要从网络上下载

小数据集

  • datasets. load_iris ()
    加载并返回鸢尾花数据集
  • datasets. load_boston ()
    加载并返回波士顿房价数据集

大数据集

  • sklearn. datasets. fetch_20 newsgroups (data_home=None, subset='train')
    • 其中的 train 为训练的数据集,还可以为 test 为测试的数据集,所有的就是 all,一般选择的是这个

数据集返回值

上述的返回的数据类型都是字典类型,可以使用 [""] 的方式获取,或者使用 . 的方式获取

  • data:特征数据数组
  • targets:标签数组
  • DERCR:数据描述
  • feature_names: 特征名
  • target_names:标签名
Python
from sklearn.datasets import load_iris
# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花数据集的返回值: \n", iris)
print("返回值是一个继承自字典的Bench")
print("鸢尾花的特征值:\n", iris["data"])
print("鸢尾花的目标值: \n", iris.target)
print("鸢尾花特征的名字: \n", iris.feature_names)
print("鸢尾花目标值的名字: \n", iris.target_names)
print("鸢尾花的描述: \n", iris.DESCR)

首先使用下面的代码输出所有的数据

Python
1
2
3
4
5
6
7
8
from sklearn.datasets import load_iris  
# 获取鸢尾花数据集  

def datasets_demo():  
    iris = load_iris()  
    print("鸢尾花数据集:\n",iris)  
    return None  
datasets_demo()
输出的结果为 :


使用

Python
print("查看数据集描述:\n",iris["DESCR"])

输出了数据集的特征

输出的特征

sepal length: 4.3 7.9 5.84 0.83 0.7826

sepal width: 2.0 4.4 3.05 0.43 -0.4194

petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)

petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)

print("查看特征值的名字,\n",iris.feature_names)
输出的结果就是:['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

数据集的划分

机器学习的数据集一般会分为两个部分:
- 训练数据:用于训练、构件模型 - 测试数据:在模型检验时使用,用于评估模型是否有效
划分的比例:
- 训练集:70.75.80 - 测试集:上面的相减


划分

  • sklearn. model_selection. train_test_split (arrays, *options)
    • x 数据集的特征值
    • y 数据集的标签值
    • test_size:测试集的大小,一般为 float
    • random_state:随机数种子,不同的种子生成不同的随机采样数,相同的种子采样结果相同
    • return 训练集特征值,测试集特征值,训练集目标值,测试集目标值
Python
from sklearn.datasets import load_iris  
from sklearn.model_selection import train_test_split  
# 获取鸢尾花数据集  

def datasets_demo():  
    iris = load_iris()  
    # print("鸢尾花数据集:\n",iris)  
    # print("查看数据集描述:\n",iris["DESCR"])  
    # print("查看特征值的名字,\n",iris.feature_names)  
    # 数据集划分  
    x_train,x_test,y_train,y_test=train_test_split(iris.data,iris.target,test_size=0.2)# 默认的情况下是0.25  
    print("训练集的特征值为\n",x_train,x_train.shape)# 后一个是输出数据集的行数

通过这种方式输出,获取测试集和训练集的特征值和标签值(就是字典的标签和特征)

特征工程的介绍

使用的算法,特征工程导致的效果的差别


数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限

什么是特征工程

什么

使用专业的背景知识和技巧处理数据,使得特征能在机器学习中更好地作用。

使用的是:

  • sklearn:特征工程
  • pandas:数据清洗、数据处理
    包括:
    特征抽取
    特征预处理
    特征降维

特征提取

什么事特征提取呢

有一个数据集

使用机器学习算法——统计方法——数学公式(但是数学公式不能处理字符串)

所以需要将数据集中的字符串转换为数值的类型


所以需要的转换: - 字典特征提取(特征离散化) - 文本特征提取 - 图像特征提取(深度学习介绍的)

字典特征提取

对字典数据进行特征值化

  • sklearn.feature_extraction.DictVectorizer(sparse=True,...)
    • vector:(数学中向量,物理中的矢量)
      使用矩阵进行存储(matrix),也就是使用二维数组进行存储
      向量是一维数组
      所以每一个样本就是一个向量,n 个样本就形成了举证
    • 父类:转换器类
      DictVectorizer. fit_transform (X):字典或者是包含字典的迭代器返回值,返回 spare 矩阵

实际上

就是将字典中的类别转换为 one-hot 编码

使用的方法

  1. 引入下面的:from sklearn.feature_extraction import DictVectorizer 抽取的代码
  2. 加上下面的:
Python
def dict_demo():  
    data = [  
        {'city': '北京', 'temperature': 100},  
        {'city': '上海', 'temperature': 60},  
        {'city': '深圳', 'temperature': 30}  
    ]  
#     1、实例化一个转化器类  
    transfer=DictVectorizer()  
    # 2、 调用fit_transform()  
    data_new=transfer.fit_transform(data)  
    print("data_new:",data_new)  
dict_demo()
  1. 最后的输出结果为:

为什么会出现这种结果?
这个我们就需要分析一下了
主要是因为上面有着默认sparse=True,... (在什么都不加的时候)
所以将上面的代码中的一句改为 transfer=DictVectorizer(sparse=False) 这种,输出结果就对了


上面的两种形式是等价的

这个是稀疏矩阵,两行是一组

特点

将非零值使用位置来表示出来

比如前两行,1 的位置是(1,0),100 的位置是(0,3)

这种的目的是什么呢

种类非常多时,0 就会非常多,所以使用这种方法可以节省内存

通过这样 print("特征名字:\n",transfer.get_feature_names_out()) 输出特征名字
输出的结果为:
特征名字:
['city=上海' 'city=北京' 'city=深圳' 'temperature']

所以对于字典中的特征都进行了 one-hot 编码

应用场景

  1. 数据集中的类别特征比较多时
    1. 将数据集的特征——>字典类型
    2. DictVectorizer 类型转换
  2. 本身拿到的数据的类型就是字典类型

文本特征提取

  • 将单词作为特征来分类是比较合理的
  • 句子、单词、短语、字母中
    这些中使用单词作为特征
    特征:特征词

方法

  1. sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
    1. 返回词频矩阵
  2. CountVectorizer.fit_transform(X),X:文本或者是包含文本字符串的可迭代对象,返回值:返回 sparse 矩阵
  3. CountVectorizer.inverse_transform(X):X 为 array 数组或者是 sparse 矩阵,返回值为:转换之前的数据格

举例:
首先引入下面的:from sklearn.feature_extraction.text import CountVectorizer
其次加上下面的代码:

Python
def count_demo():  
    """  
    文本特征抽取:countvectorizer  
    :return:    """    data = ["life is short,i like like python",  
     "life is too long,i dislike python"]  

    # 1.实例化一个转换器类  
    transfer=CountVectorizer()  
    # 2.调用fit_transform  
    data_new=transfer.fit_transform(data)  
    print("data_new:\n",data_new.toarray())  
    print("特征名字:\n",transfer.get_feature_names_out())  
    return None  
count_demo()
最后的结果为
data_new:
[[0 1 1 2 0 1 1 0]
[1 1 1 0 1 1 0 1]]
特征名字:
['dislike' 'is' 'life' 'like' 'long' 'python' 'short' 'too']


  1. CountVectorizer () 的方法
    统计每个样本特征出现的次数(不统计单个的字母和标点符号)
    stop_words 停用的词,可以将觉得没有用处的词以列表的形式传进去
    还有专门的停用词表
    例如 transfer=CountVectorizer(stop_words=["is","to"]),最后的输出结果就是没有 is 和 to 了

出现的是中文的文本时怎么办

就直接将里面的英文改为中文

但是最后的输出结果为

[[0 1]

[1 0]]

特征名字:

['天安门上太阳升' '我爱北京天安门']

所以要有需要的效果的话,需要使用空格隔开对应的词语

data = ["我爱北京天安门",

"天安门上太阳升"]

最后的输出结果变成了:

还是没有管单个的词语
用于分词的可以使用结巴分词,或者之后使用一些专业的库进行分词

文本特征提取的其他方法

首先使用清华镜像网站安装 jieba(在内部的终端中)pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple/ ,并在开头进行引用


首先看一下这个的功能

Python
1
2
3
4
5
6
7
8
import jieba #调用
def cut_word(text):  
    """  
    进行中文分词:"我爱北京天安门"->"我 爱 北京 天安门"  
    :param text:    :return:    """    a=" ".join(list(jieba.cut(text)))#此时是生成器的形式,要强制转换为列表的形式  
    print(a)  
    print(type(a))  
    return a
上面函数的输出结果为

结果

我爱北京天安门

其中的" ".join (list (jieba.cut (text))) 的意思是

  1. jieba.cut(text):使用 jieba 库的 cut 方法对文本 text 进行分词,返回一个可迭代的分词结果(生成器)

  2. list(jieba.cut(text)):将分词结果转换为列表,每个元素是一个词语。

  3. " ".join(...):用空格作为分隔符,将列表中的所有词语拼接成一个完整的字符串。


之后就可以自动的中文分词,中文

Python
def cout_chinese_demo():  
    """  
    中文文本的特征抽取  
    :return:    """    data=["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",  
          "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",  
          "如果只用一种方式了解某样事物,你就不会真正了解它。解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]  
    # 1、将中文文本进行分词  
    data_new=[]  
    for sent in data:  
        data_new.append(cut_word(sent))  
    # 2、实例化一个转换器类  
    transfer=CountVectorizer(stop_words=["一种","所以"])  
    # 3、调用fit_transfrom,输出的结果为矩阵  
    data_f=transfer.fit_transform(data_new)  
    print("data_new:\n",data_f.toarray())  
    print("特征名字:\n",transfer.get_feature_names_out())  
    return None  
# cut_word("我爱北京天安门")  
cout_chinese_demo()
实际上就是多了一步,除此之外还多了一个函数
最后的输出结果为

但是这个输出结果的顺序排的不好,因为我们会想把出现次数高的排在前面

新的提取方法——TF-idf 文本特征提取

关键词:在某一个类别文章中,出现的次数很多,但是在其他类别的文章中出现的很少

  • 主要的思想:某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词具有很好的类别区分能力,适合用来分类
  • 作用:用于评估一字词对于某一文件集或者一个语料库中的其中一份文件的重要程度

  • TfdfVectorize
    TF-IDF——重要程度
    例如:两个词:“经济”,“非常”
    一共 1000 篇文章
    其中 100 篇文章有“非常
    10 篇文章——“经济”
    两篇文章:
    文章 A(100 词):10 次“经济”:0.2
    TF:10/100=0.1
    idf=lg 1000/10=2
    文章 B(100 词):10 次“非常” : 0.1
    TF: 10/100=0.1
    idf: log 10 (1000/100)=1

公式:

  • 词频(TF)指的是给定的词语在该文件中出现的频率
  • 逆向文档频率(idf):一个词语普遍重要性的度量——由总文件数目除以包含该词语文件的数目,再将得到的商取以 10 为底的对数
    最后的计算公式:(两个数值相乘即可)
\[ \mathrm{tfidf_{i,j}=tf_{i,j}\times idf_i} \]

最后得到的结果就是重要程度

API

  • sklearn.feature extraction.text.TfidfVectorizer(stop words=None,...) 实例化
  • 返回词的权重矩阵
    • TfidfVectorizer.fitttransform(X)
      x: 文本或者包含文本的字符串的可迭代对象
      返回值:返回 sparse 矩阵(使用 toarray 变为数组的形式)

加上后面的 from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
再有后面的代码:

Python
def tfidf_demo():  
    """  
    使用tf-idf的方法进行文本特征提取  
    :return:    """    data=["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",  
          "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",  
          "如果只用一种方式了解某样事物,你就不会真正了解它。解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]  
    # 将中文文本进行分词  
    data_new=[]  
    for sent in data:  
        data_new.append(cut_word(sent))  
    # 实例化一个转换器类,新的转换器  
    transfer=TfidfVectorizer(stop_words=["一种","所以"])  #主要改这个地方
    # 调用fit_transfrom  
    data_f=transfer.fit_transform(data_new)  
    print("data_new:\n",data_f.toarray())  
    print("特征名字:\n",transfer.get_feature_names_out())  
    return None

最后的输出结果

特征预处理

什么是特征预处理

通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程

  • 包含内容
    数值型数据的无量纲化
    • 归一化
    • 标准化
  • 特征预处理 API:sklearn.preprocessing

我们为什么要进行归一化?
使用距离公式计算两个样本之间的距离,但是由于某一特征的数值过大,导致距离取决于数值大的特征,但是我们现在认为特征是同等重要的
所以我们用到无量纲化,使得特征变为同一规格

归一化

定义
通过对原始数据进行变换把数据映射到默认的[0,1]之间
定义

\[ X^{\prime}=\frac{x-min}{max-min}\quad X^{\prime\prime}=X^{\prime}*(mx-mi)+mi \]

说明

作用于每一列,max 为一列的最大值,min 为一列的最小值,\(x^{''}\) 为最终的结果

mx, mi 分别为指定区间,默认 mx 为 1,mi 为 0

实际上就是将每一列的数值放缩平移到数轴上的[0,1]区间

方法

  • sklearn.preprocessing.MinMaxScaler (feature range=(0,1)...)
    • MinMaxScalar.fit transform(X)
      • x: numpy array 格式的数据 [n_samples, n_features](就是一个数组)
    • 返回值:转换后的形状形同的 array

例子:

方法

  • 首先使用 panda 函数获取数据:data=pd.read_csv("dating.txt",sep='\t'),panda 也是需要安装的,其中的 dating. text 文件必须在同样的目录下
  • 实例化转化器类:
    • 头文件:from sklearn.preprocessing import MinMaxScaler
    • transfer=MinMaxScaler(feature_range=(2,3))
    • data_new=transfer.fit_transform(data)
      最后的代码:

    调用转化:

    Python
    def minmax_demo():  
        """  
        归一化  
        :return:    """#     1. 获取数据  
        data=pd.read_csv("dating.txt",sep='\t')  
        print("data:\n",data)  
        data=data.iloc[:,:3]  
    # 2.实例化一个转换器类  
        transfer=MinMaxScaler(feature_range=(2,3))  
    
    # 3. 调用fit_transform转化  
        data_new=transfer.fit_transform(data)  
        print("data_new:\n",data_new)  
        return None
    

输出结果

data_new:
[[2.43582641 2.58819286 2.53237967]
[2. 2.48794044 3. ]
[2.19067405 2. 2.43571351]
[3. 3. 2.19139157]
[2.3933518 2.01947089 2. ]]


分析一下上面的有什么缺点
如果有异常值的话,一般是最大值或者是最小值产生异常
而我们归一化的时候使用的就是最大值和最小值,非常容易受到异常值的影响
所以这种方法的鲁棒性非常差,只适合传统精确小数据的场景

标准化

  • 定义:
    对原始数据变换为均值为 0,标准差为 1 的范围内
  • 公式

    \[ X^{\prime}=\frac{x-\mathrm{mean}}{\sigma} \]

    mean 为平均值,\(\sigma\) 为标准差

所以我们现在再看一下,异常值在有大量数据的情况下不会使标准差产生太大的影响


  • sklearn.preprocessing.StandardScaler( )
    • 处理之后,每列数据都聚焦在均值为 0. 标准差为 1 的
    • StandardScaler.fit_transform(X)
      • X:numpy array 格式的数据(数组形式的)
    • 返回值:转换后形状形同的 array

步骤

  • 在头文件中加上:from sklearn.preprocessing import MinMaxScaler,StandardScaler
  • 加上下面的代码:
Python
def stand_demo():  
    """  
    标准化  
    :return:    """    #     1. 获取数据  
    data = pd.read_csv("dating.txt", sep='\t')  
    print("data:\n", data)  
    data = data.iloc[:, :3]  
    # 2.实例化一个转换器类  
    transfer = StandardScaler()  

    # 3. 调用fit_transform转化  
    data_new = transfer.fit_transform(data)  
    print("data_new:\n", data_new)  
    return None  
stand_demo()
  • 最后的输出结果为

特征降维

降维

  • 降维:字面上就是降低维度
    对于数组来说:维数就是数组嵌套的数目
    0 维就是标量(数字)
    1 维向量
    2 维矩阵
    n 维
  • 二维数组
    此处的降维:降低特征的个数
    得到一组不相关的主要变量的过程(极大线性无关组)
  • 相关特征:
    • 相对湿度和降雨量相关
    • 等等,有很多数据是相关的,有很多冗余的数据

降维的两种方法

  • 特征选择
  • 主成分分析

特征选择

  • 定义:
    数据中包含冗余和相关变量,旨在从原有的特征中找出主要的特征
  • 方法:
    • 过滤式(filter):
      方差选择法:低方差特征过滤
      相关系数:衡量两个特征之间的相关性(相关程度)
    • 嵌入式:
      决策树——第二天的内容
      正则化——第三天的内容
      深度学习——第五天的内容

过滤式

低方差特征过滤

删除低方差的一些特征

  • API:
    • sklearn.feature_selection.VarianceThreshold(threshold=0.0)
      • 删除所有的低方差特性(阈值就是后面括号内的值,低于那个的都删掉,默认为 0)
      • {Variance.fit transform(X)
        x: 为数组
        默认的返回值为所有非 0 的方差特征,即删除所有样本中具有相同值的特征

步骤

  1. 在头部引入头文件:from sklearn.feature_selection import VarianceThreshold
  2. 下面的代码

    Python
    def variance_demo():  
        """  
        过滤低方差特征  
        :return:    """    #     获取数据  
        data=pd.read_csv("va.csv")  
        data=data.iloc[:,3:-1]  
        print("data:\n",data)  
        # 实例化一个转换器类  
        transfer=VarianceThreshold(threshold=1000)  
        # 调用fit_transform  
        data_new=transfer.fit_transform(data)  
        print("data_new:\n",data_new,data_new.shape)  
        return None
    
  3. 最后的输出结果为:(要注意调整输出特征的条件)

相关系数的求法

  • 皮尔逊相关系数
    • 反应变量之间相关关系密切程度的统计指标
  • 公式

    \[ r=\frac{n\sum xy-\sum x\sum y}{\sqrt{n\sum x^2-(\sum x)^2}\sqrt{n\sum y^2-(\sum y)^2}} \]

    值的绝对值越接近 1,则两个变量的相关程度越大

方法

  • 在前面引入:from scipy.stats import pearsonr
  • 加上下面的代码:
Python
1
2
3
4
5
# 计算两个变量之间的相关系数  
r1=pearsonr(data["quantity"],data["unit_price"])  
print("r:\n",r1)  
r2=pearsonr(data["total_sales"],data["unit_price"])  
print("r:\n", r2)

计算之后的相关性很高的特征怎么办

  1. 选择其中的一个
  2. 加权求和
  3. 主成分分析
    从而将相关性高的成分处理掉

主成分分析

什么是主成分分析

  • 定义:将高维数据转化为低位数据的过程中,可能会有舍弃原有的数据,创造新的变量的过程
  • 作用:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息
  • 应用:回归分析或者聚类分析当中

我们在拍出三维的视图时,在将三维降到二维的过程中,怎么弄使得信息的损失最少(降维后的信息保留原有的特征)

将二维的数据转化为一维的时候,找到一个合适的直线,通过矩阵运算得出主成分分析的结果

API

怎么在 sklearn 中使用

  • sklearn.decomposition.PCA(n_components=None)
    • 将数据分解为较低维数空间
    • n_components:
      • 小数:表示保留百分之多少的信息
      • 整数:减少到多少的特征
    • PCA. fit_transform (X)
    • 返回值为:转换后指定维度的 array

计算

代码

  • 开头调用:from sklearn.decomposition import PCA
  • 之后的代码:
Python
def pca_demo():  
    """  
    pca降维  
    :return:    """    data=[2,8,4,5],[6,3,0,8],[5,4,9,1](2,8,4,5],[6,3,0,8],[5,4,9,1.md){#e2a168d4a18e20f238432327edc0afe2}  

    #实例化一个转化器  
    transfer=PCA(n_components=0.95)  #保留了95%的信息

    #调用  
    data_new=transfer.fit_transform(data)  
    print("data_new:\n",data_new)  
    return None

最后的输出结果:

结果

data_new:

[[-1.28620952 e-15 3.82970843 e+00]

[-5.74456265 e+00 -1.91485422 e+00]

[ 5.74456265 e+00 -1.91485422 e+00]]

案例分析:探究用户对物品类别喜好的细分

用户物品类别之间的关系

  1. 需要将 user_id 和 aisle 放在同一个表中
  2. 将行索引变为用户 ID,列索引变为某一物品的数量(检查表和透视表)
  3. 特征冗余过多——>PCA 降维

合并

  1. 合并 aisles 和 products, 使用 pd.merge
  2. aisles 和 products 是两个要合并的 DataFrame(数据表)
  3. on=["aisle_id","aisle_id"] 指定了合并的依据是这两个 DataFrame 中都存在的 aisle_id 列
    简单说,这段代码的作用是:根据 aisle_id 这一列,将 aisles 和 products 两个数据表中相关联的记录合并到一起,生成一个新的数据表 tab1

笔记

  1. 首先应该安装 jupyter,在 cmd 中使用 pip 安装
  2. 之后在 cmd 中打开,选择打开的目录为数据所在的文件 jupyter notebook --notebook-dir=D:\dev\pythonProject1
  3. 引入头文件,读取数据:
    Python
    !pip install pandas  
    import pandas as pd  
    
  4. 进行数据的读取:
    Python
    1
    2
    3
    4
    products=pd.read_csv("./archive/products.csv")  
    order_products=pd.read_csv("./archive/order_products__prior.csv")  
    orders=pd.read_csv("./archive/orders.csv")  
    aisles=pd.read_csv("./archive/aisles.csv")  
    
  5. 进行多次的数据的合并
    tab1 = pd.merge(aisles,products, on=["aisle_id","aisle_id"])
    tab2 = pd.merge(tab1 , order_products, on="product_id")
    tab3=pd.merge(tab2,orders,on="order_id")
  6. 找到所需数据之间的关系(# 3. 找到 user_id 和 aisle 之间的关系)
    table = pd.crosstab(tab3["user_id"],tab3["aisle"])
  7. 之后进行数据的降维(之前的内容)(为了简化,可以取一部分)
    data=table[:20000]

206209 rows × 134 columns 这是原始的数据,经过简化之后的数据为

可见,在 95%的简化之后,列数据减少了很多

总结

分类算法

目标值:类别的话就是分类算法

sklearn 的转换器和预估器

转换器

我们之前一直在用的就是转换器(特征工程的父类)

  1. 实例化(就是一个转换器类)
  2. 调用 fit_transform(先是 fit,之后是 transform)
  3. 在标准化的时候
    1. fit:计算每一列的平均值和标准差
    2. transform:带入公式中进行最终的转换

估计器

估计器 (estimator),是一类实现了算法的 API

步骤

  1. 实例化一个 estimator
  2. estimator. fit (x_train, y_train), 这里的 fit 也是在计算
    1. 调用完毕之后模型已经生成了
  3. 模型的评估:
    1. 直接比对真实值和预测值
      y_predict=estimator. predict (x_test)
      y_test==y_predict
    2. 计算准确率
      estimator. score (x_test, y_test)

K-近邻算法(KNN 算法)

什么是

通过你的邻居判断出你的类别

  • 原理:
    一个样本中在特征空间中的 k 个最相似(即特征空间中最临近)的样本中的大多数属于某一个类别,则该样本也属于这个类别
    但是 k=1 的时候容易收到异常值的影响
  • 计算距离:
    距离公式,我们在几何中常用的欧式距离

    \[ \begin{aligned}&\text{a(a1,a2,a3),b(b1,b2,b3)}\\&\sqrt{(a1-b1)^{2}+(a2-b2)^{2}+(a3-b3)^{2}}\end{aligned} \]

    还有曼哈顿距离:就是绝对值距离
    明可夫斯基距离 - 电影类型分析
    k=1:爱情片(最近的已知电影)
    k-2:爱情片
    ……
    k=6 时,不行,因为已知的一共只有六个
    当我们的 k 值取值过大时,容易分错(样本不均衡的时候,容易收到影响) - 同样,像之前一样,因为要有求距离,所以需要无量纲化处理 - 使用标准化无量纲化处理


k-近邻算法 API

  • sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto')
    • n_neighbors: int, 可选(默认= 5),k_neighbors 查询默认使用的邻居数 (这就是 k 值)
    • algorithm: {'auto', 'ball_tree', 'kd_tree', 'brute'},可选用予计算最近邻居的算法:'ball_tree' 将会使用 BallTree'kd_tree' 将会使用 KDTree'auto' 将尝试根据传递给 fit 方法的值来决定最合适的算法。(不同实现方式影响效率)

案例:鸢尾花案例

步骤

  1. 获取数据
  2. 数据集划分
  3. 特征工程
    1. 标准化
  4. KNN 预估器流程
  5. 模型评估

代码:

Python
from sklearn.datasets import load_iris  # 引入数据
from sklearn.model_selection import  train_test_split  # 模型划分
from sklearn.neighbors import KNeighborsClassifier  # KNN算法
from sklearn.preprocessing import StandardScaler  # 标准化


def knn_iris():  
    """  
    使用算法对鸢尾花进行分类  
    :return:    """    # 获取数据  
    iris=load_iris()  
    # 划分数据集  
    x_train,x_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=22)  

    # 标准化  
    transfer=StandardScaler()  
    x_train=transfer.fit_transform(x_train)# 对训练集进行标准化  
    x_test=transfer.transform(x_test)  
    # 算法预估器  
    estimator=KNeighborsClassifier(n_neighbors=3)  
    estimator.fit(x_train,y_train)  
    # 模型评估  
        # 方法一:比较真实值和预测值  
    y_predict=estimator.predict(x_test)  
    print("y_predict:\n",y_predict)  
    print("直接比较的准确率:\n",y_test==y_predict)  
        # 方法二:计算准确率  
    score=estimator.score(x_test,y_test)  
    print("准确率为\n",score)  
    return None  
# 代码1:KNN算法鸢尾花分类  
knn_iris()

总结

  • 优点:
    • 简单,易于理解,易于实现,无需训练
  • 缺点:
    • 懒惰算法:对测试样本分类是的计算量大,内存开销大
    • 必须指定 k 值,k 值选择不当则分类精度不能保证
  • 使用场景:小数据场景

模型选择与调优

什么是交叉验证

交叉验证:将得到的训练数据分为训练和验证集: 将数据氛围 4 分。其中的一份作为验证集,然后进行 4 次测试,每次都换不同的验证集,即得到 4 组模型的结果,取平均值作为最终的结果

针对训练集进行这样的划分,从而使得训练得出的模型更加准确

超参数网格搜索

有很多参数是需要手动指定的(k),手动过程过于复杂,所以需要对模型预设几种超参数组合。每组超参数使用交叉验证,得到最有效的参数

模型选择与调优 API

  • sklearn.model_selection.GridSearchCV(estimator, param_grid=None, cv=None)
    • 对估计器的指定参数值进行详尽搜索
    • estimator:估计器对象 (也是一个预估器的类)
    • param_grid:估计器参数(dict,如 {"n_neighbors": [1, 3, 5]} )(k 的取值,使用字典来传进来)
    • cv:指定几折交叉验证
    • fit():输入训练数据
    • score():准确率
    • 结果分析:
      • 最佳参数:best_params_
      • 最佳结果:best_score_
      • 最佳估计器:best_estimator_
      • 交叉验证结果:cv_results_

与上一节相比更改的地方:

  1. 导入新的库
    Python
    from sklearn.model_selection import GridSearchCV
    
  2. 算法预估器变为下面的形式:
    Python
    1
    2
    3
    4
    5
    6
    7
    # 算法预估器  
    estimator=KNeighborsClassifier()  
    # 加入网格搜索和交叉验证  
    # 参数准备  
    param_dict={"n_neighbors":[1,3,5,7,9,11]}  
    estimator=GridSearchCV(estimator,param_grid=param_dict,cv=10)  
    estimator.fit(x_train,y_train)
    
  3. 最后的输出结果更加丰富
    Python
    1
    2
    3
    4
    5
    6
    7
    8
    # 最佳参数:`best_params_`  
    print("最佳参数:\n",estimator.best_params_)  
    # 最佳结果:`best_score_`  
    print("最佳结果:\n", estimator.best_score_)  
    # 最佳估计器:`best_estimator_`  
    print("最佳估计器:\n", estimator.best_estimator_)  
    # 交叉验证结果:`cv_results_`  
    print("最佳交叉验证结果:\n", estimator.cv_results_)
    

输出结果:

我们现在的流程已经全部有了

预测 facebook 签到位置

kaggle 上的比赛

  • train. csv. test. csv
    • x, y 坐标
    • 准确性:定位准确性
    • 时间:时间戳
    • place_id:业务的 ID,预测的目标
      还是使用 D:\dev\pythonProject1>jupyter notebook 新建(右侧)python 3
      这个 jupyter 好像是一步步手动运行的

步骤

  1. 数据的处理:(特征值 x 和目标值 y)
    1. 缩小数据范围的处理(将 x 的坐标放在 2,2.5,y 放在 1,1.5 之间)data=data.query("x<2.5&x>2&y>1&y<1.5") data
    2. (b.time->年月日和时分秒),使得时间有意义化
    3. 过滤签到次数少的地点
  2. 特征工程:标准化
  3. KNN 算法预估流程
  4. 模型选择与调优
  5. 模型评估

注意这个课程是需要在看完数据分析与挖掘基础之后再来学习的,数据分析课程下边会有链接点击后直接跳转至此课程的


发现最难的地方还是在数据处理上

朴素贝叶斯算法

什么是朴素贝叶斯算法的分类方式

KNN 直接出分到哪一类了
但是朴素贝叶斯算法分完之后是各种结果的概率值

概率的基础知识

  • 概率的定义:
    • 一件事情发生的可能性
      • 扔出一个硬币,结果头像朝上的可能性
    • P (X):取值在[0,1]

相互独立的定义,还有贝叶斯公式

\[ P(C|W)=\frac{P(W|C)P(C)}{P(W)} \]
  • 朴素贝叶斯算法:
    朴素+贝叶斯
    朴素就是假定特征之间是相互独立的
    贝叶斯就是贝叶斯公式
  • 应用场景:
    文本分类(以单词作为特征,词与词之间是相互独立的)
\[ P(C|F1,F2,...)=\frac{P(F1,F2,...|C)P(C)}{P(F1,F2,...)} \]

也就是这里的 \(F_1,F_2\) …… 这些是相互独立的,所以右边分子上的条件概率可以分开计算(乘出来)

\[ 变为P(F_1|C)P(F_2|C)…… \]

但是当这里的乘的一项为 0 时怎么办(样本的数据太少):

  • 拉普拉斯平滑系数:

    \[ P(F1|C)=\frac{Ni+\alpha}{N+\alpha m} \]

    \(\alpha\) 为指定的系数,一般为 1,m 为训练集(不仅仅是 C 集)中统计出的特征词的个数(特征词的种类),\(Ni\) 为该特征 F₁ 在类别 C 中出现的次数
    N 通常表示在类别 C 中所有特征(或词语)出现的总次数,也就是类别 C 下的样本总量(或词频总和)
    必须是在 C 集的条件下

API

  • sklearn. naive_bayes.MultinomialNB (alpha = 1.0)
  • 朴素贝叶斯分类
  • alpha: 拉普拉斯平滑系数

案例:20 类新闻分类

步骤

  1. 获取数据 from sklearn.datasets import fetch_20newsgroups
  2. 划分数据集(文字的)from sklearn.feature_extraction.text import TfidfVectorizer
  3. 特征工程
    文本特征抽取
  4. 朴素贝叶斯预估器流程 from sklearn.naive_bayes import MultinomialNB
  5. 模型评估

代码:

Python
def nb_news():  
    """  
    朴素贝叶斯算法新闻分类  
    :return:    """    # 1获取数据  
    news=fetch_20newsgroups(subset="all")  
    #2. 划分数据集  
    x_train,x_test,y_train,y_test=train_test_split(news.data,news.target)  
    #3. 文本特征抽取  
    transfer=TfidfVectorizer()  
    x_train=transfer.fit_transform(x_train)  
    x_test=transfer.transform(x_test)  
    # 朴素贝叶斯算法预估器  
    estimator=MultinomialNB()  
    estimator.fit(x_train,y_train)  
    # 模型评估  
    # 方法一:比较真实值和预测值  
    y_predict=estimator.predict(x_test)  
    print("y_predict:\n",y_predict)  
    print("直接比较的准确率:\n",y_test==y_predict)  
    # 方法二:计算准确率  
    score=estimator.score(x_test,y_test)  
    print("准确率为\n",score)  
    return None

总结

  • 优点:
    • 有稳定的分类效率
    • 对缺失的数据不敏感
    • 分类准确度高,速度快
  • 缺点:
    • 由于使用了样本属性独立性的假设,所以如果特征属性有关联时其效果不好

决策树

认识决策树

决策树,就是 if-else 的方式进行分类

决策树的分类原理详解

怎么知道原理的先后

已知四个特征,预测是否贷款给某个人

  • 有房子的都是
    • 在没有房子的里面:有工作的都是
      已经能决定是否贷款了
  • 先看年龄,再看信贷情况,最后看工作看了三个特征
  • 所以可以看出最高效的特征为第一种

原理

  • 信息熵:信息增益
  • 信息熵的定义:
    • H 的专业术语称之为信息熵,单位为比特

      \[ H(X)=-\sum_{i=1}^nP(x_i)logbP(x_i)) \]

  1. 信息:消除随机不确定性的东西
    小明年龄:今年 18 岁(是信息)
    小华说小明明年 19 岁(在上面的基础上的推论,不是信息)
  2. 如何量化信息量:
    信息熵:\(H(X)=-\sum_{i=1}^nP(x_i)logbP(x_i))\),这里对数的底数一般是 2

已知某人的年龄,工作,房子,信贷情况等等,消除是否贷款的不确定性
怎么使用上面的信息熵的公式求出 H (x)?

\[ \bar{H}(\text{总})=-(6/15^{\star}\log6/15+9/15^{\star}\log9/15) \]
  1. 信息增益:

    \[ g\left(D,A\right)=H\left(D\right)-H\left(D\right|A) \]

    计算公式

    \[ H(D|A)=\sum_{i=1}^n\frac{|D_i|}{|D|}H(D_i)=-\sum_{i=1}^n\frac{|D_i|}{|D|}\sum_{k=1}^K\frac{|D_{ik}|}{|D_i|}\log\frac{|D_{ik}|}{|D_i|} \]

    使用总的信息熵减去知道某个信息之后的信息熵就是信息增益
    例如上面的例子中,知道年龄之后的信息增益为为
    A 是用于划分数据集的特征,如年龄,性别等,将数据集 D 划分为多个子集
    特征 A 取第 i 个值时,对应的样本子集(如 A 是 “性别”,D₁= 男性样本,D₂= 女性样本)

决策树的 API

  • class sklearn.tree.DecisionTreeClassifier (criterion='gini', max_depth=None, random_state=None)
  • 决策树分类器
  • criterion: 默认是'gini'系数,也可以选择信息增益的熵'entropy'
  • max_depth: 树的深度大小(深度过大的话会过拟合)
  • random_state: 随机种子

过拟合会导致模型泛化能力差,即过度适合当前样本集而缺乏适应(预测)新样本的能力

完整的代码:

Python
def decision_iris():  
    """  
    用决策树对鸢尾花进行分类  
    :return:    """    # 1. 获取数据集  
    iris=load_iris()  
    # 2. 划分数据集  
    x_train,x_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=22)  
    # 3. 决策树预估器  
    estimator=DecisionTreeClassifier(criterion="entropy")  
    estimator.fit(x_train,y_train)  
    # 4,模型评估  
        # 方法一:比较真实值和预测值  
    y_predict=estimator.predict(x_test)  
    print("y_predict:\n",y_predict)  
    print("直接比较的准确率:\n",y_test==y_predict)  
        # 方法二:计算准确率  
    score=estimator.score(x_test,y_test)  
    print("准确率为\n",score)

新加的头文件:from sklearn.tree import DecisionTreeClassifier

决策树的可视化

保存树的结构到 dot 文件

  • sklearn. tree. export_graphviz () 该函数能够导出 DOT 格式
  • tree. export_graphviz (estimator, out_file="tree. dot", feature_names=[""])
    estimator:所求的预估器
    out_file="tree. dot":路径

之后需要借助网站显示文本文件

步骤

  • from sklearn.tree import DecisionTreeClassifier,export_graphviz
    Python
    # 可视化决策树  
    export_graphviz(estimator, out_file="iris_tree.dot")  
    

但是没有分类的特征名字:
export_graphviz(estimator, out_file="iris_tree.dot",feature_names=iris.feature_names)
这样就有特征的名字了

查看的网址:
https://dreampuf.github.io/GraphvizOnline/

最后的树:

总结

  • 优点:
    • 简单,易于理解
    • 可视化-可解释能力强(深度学习神经网络相反)
  • 缺点
    • 处理过于复杂的网络时,容易发生过拟合
  • 改进:
    • 剪枝 cart 算法
    • 随机森林

泰坦尼克号乘客生存的预测案例

  1. 获取数据
  2. 数据处理
    1. 缺失值处理
    2. 有多个特征是类别,将特征值转换为字典类型的
    3. 筛选特征值和目标值
    4. 划分数据集
    5. 特征工程:字典特征获取
    6. 决策树预估器流程
    7. 模型评估
      最后的输出结果:

代码

Python
1
2
3
# 2. 数据处理  
# 1. 缺失值处理  
x["Age"].fillna(x["Age"].mean(),inplace=True)  
Python
# 2.转换为字典
x=x.to_dict(orient="records")
Python
1
2
3
4
# 检查y中是否有缺失值
print("缺失值数量:", pd.isna(y).sum())
# 查看缺失值的位置
print("缺失值索引:", pd.isna(y).where(pd.isna(y)).dropna().index.tolist())
Python
1
2
3
# 划分后转换(推荐方法 1,更彻底)
y_test = y_test.iloc[:, 0]  # 取第一列转为 Series
y_train = y_train.iloc[:, 0]
Python
# 3. 决策树预估器
from sklearn.tree import DecisionTreeClassifier, export_graphviz
estimator=DecisionTreeClassifier(criterion="entropy",max_depth=8)# 设置了树的最大深度
estimator.fit(x_train,y_train)
# 4,模型评估
    # 方法一:比较真实值和预测值
y_predict=estimator.predict(x_test)
print("y_test 类型:", type(y_test))  # 应显示 <class 'pandas.core.series.Series'>
print("y_test 形状:", y_test.shape)  # 应显示 (n,)(一维)
print("y_predict:\n",y_predict)
print("直接比较的准确率:\n",y_test==y_predict)
    # 方法二:计算准确率
score=estimator.score(x_test,y_test)
print("准确率为\n",score)
# 可视化决策树
export_graphviz(estimator, out_file="titan_tree.dot",feature_names=transfer.get_feature_names_out())

随机森林

什么是集成学习方法

就是众人拾柴火焰高,生成多个分类器,进行预测,取预测的众数
例如我们训练了 5 棵树,最后取结果的众数

随机森林的原理过程

N 个样本中 M 个特征:

  1. 特征随机——从 M 个特征中随机抽取 m 个特征
    1. M>>m(起到降维的作用)
    2. 虽然我们的特征数量变少了,但是会有很多很多的树
  2. 训练集随机——每棵树的训练集是随机有放回生成的(N 个样本中随机有放回抽样 N 个)
    1. 使用 bootstrap 随机有放回抽样
      例如训练集样本为[1,2,3,4,5]
      新的训练集:[2,2,3,1,5]

API

  • class sklearn.ensemble.RandomForestClassifier (n_estimators=10, criterion='gini', max_depth=None, bootstrap=True, random_state=None, min_samples_split=2)
    • 随机森林分类器
    • n_estimators: integer, optional (default = 10) 森林里的树木数量 120,200,300,500,800,1200
    • criteria: string, 可选 (default = "gini") 分割特征的测量方法
    • max_depth: integer 或 None, 可选 (默认=无) 树的最大深度 5,8,15,25,30
    • max_features="auto", 每个决策树的最大特征数量
      • If "auto", then max_features=sqrt (n_features).(对 M 求平方根)
      • If "sqrt", then max_features=sqrt (n_features) (same as "auto").(求出平方根)
      • If "log 2", then max_features=log 2 (n_features).(2 为底的对数)
      • If None, then max_features=n_features.(取得值就是 M)
    • bootstrap: boolean, optional (default = True) 是否在构建树时使用放回抽样
    • min_samples_split: 节点划分最少样本数
    • min_samples_leaf: 叶子节点的最小样本数
  • 超参数: n_estimator, max_depth, min_samples_split, min_samples_leaf

使用

  • 头文件:
    from sklearn.ensemble import RandomForestClassifier #随机森林 from sklearn.model_selection import GridSearchCV #交叉验证
  • 在网格搜索中加上所需的参数:
    Python
    1
    2
    3
    param_dict={"n_estimators":[120,200,300,500,800,1200],  
               "max_depth":[5,8,15,25,30]}  
    estimator=GridSearchCV(estimator,param_grid=param_dict,cv=3)  
    
  • 之后进行同样的验证即可:
    Python
    estimator.fit(x_train,y_train)  
    # 模型评估  
        # 方法一:比较真实值和预测值  
    y_predict=estimator.predict(x_test)  
    print("y_predict:\n",y_predict)  
    print("直接比较的准确率:\n",y_test==y_predict)  
        # 方法二:计算准确率  
    score=estimator.score(x_test,y_test)  
    print("准确率为\n",score)  
    # 最佳参数:`best_params_`  
    print("最佳参数:\n",estimator.best_params_)  
    # 最佳结果:`best_score_`  
    print("最佳结果:\n", estimator.best_score_)  
    # 最佳估计器:`best_estimator_`  
    print("最佳估计器:\n", estimator.best_estimator_)  
    # 交叉验证结果:`cv_results_`  
    print("最佳交叉验证结果:\n", estimator.cv_results_)  
    

总结

  • 有极好的准确率
  • 有效地运行在大数据集上

回归与聚类算法

  • 回归问题:
    目标值为连续性的数据

线性回归

线性回归的原理

  • 定义:利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式(就是找到特征值和目标值之间的函数关系)
  • 特点:根据自变量的个数分为单变量回归和多元回归

通用公式:(前面的 w 为权重系数,b 为偏置)

\[ h(w)=w_{1}x_{1}+w_{2}x_{2}+w_{3}x_{3}...+\mathrm{b}=w^{T}x+b \]

其中的 w 和 x 可以理解为矩阵:

\[ \mathbf{w}=\begin{pmatrix}b\\w_1\\w_2\end{pmatrix},\mathbf{x}=\begin{pmatrix}1\\x_1\\x_2\end{pmatrix} \]
  • 线性模型:(不同于线性关系)
    参数是一次的(也就是多项式也可以是线性模型)
    自变量是一次的(线性关系)
    这两种情况都可以叫做线性模型

线性关系一定是线性模型,但是反之不一定的

线性回归的损失和优化原理(理解记忆)

有真实关系,还有假设的关系
不断地迭代,消除误差
所以怎么进行衡量呢——损失函数:cost

损失函数

定义为:

\[ \begin{aligned}J(\theta)&=(h_{w}(x_{1})-y_{1})^{2}+(h_{w}(x_{2})-y_{2})^{2}+\cdots+(h_{w}(x_{m})-y_{m})^{2}\\&=\sum_{i=1}^{m}(h_{w}(x_{i})-y_{i})^{2}\end{aligned} \]
  • y_i 为第 i 个训练样本的真实值
  • h (x_i) 为第 i 个训练样本特征值组合预测函数
  • 又称为最小二乘法

优化算法:求出损失最小时对应的 w 的值

优化算法

有两种方式:正规方程和梯度下降
正规方程:
天才——直接求解 w 的值,只求一次

\[ w=(X^{T}X)^{-1}X^{T}y \]

梯度下降:
努力的普通人——不断地试错,不断地改进,使得总损失最小

拓展内容:
函数的最小值的求法:对函数进行求导
得到导函数的零点就是

梯度下降

\[ w_{1}:=\quad w_1-\alpha\frac{\partial cost(w_0+w_1x_1)}{\partial w1}\quad w_{0}:=\quad w_0-\alpha\frac{\partial cost(w_0+w_1x_1)}{\partial w1} \]

沿着梯度下降(切线的方向),下降到最低点(微积分的思想)
但是有可能到了局部的最小点(极点,也是导函数为 0 的点,但是不是最小值)

API

API 的调用

  • sklearn. linear_model.LinearRegression (fit_intercept=True)
    • 通过正规方程优化
    • fit_intercept: 是否计算偏置(一般为 true,更加准确一点,因为没有偏置的话最后的结果必定过原点,是有局限性的)
    • LinearRegression. coef_: 回归系数
    • LinearRegression. intercept_: 偏置
  • sklearn. linear_model.SGDRegressor (loss="squared_loss", fit_intercept=True, learning_rate='invscaled', eta 0=0.01)
    • SGDRegressor 类实现了随机梯度下降学习,它支持不同的 loss 函数和正则化惩罚项来拟合线性回归模型。
    • loss: 损失类型
      • loss="squared_loss": 普通最小二乘法
    • fit_intercept: 是否计算偏置
    • learning_rate: string, optional
      • 学习率填充
      • 'constant': eta = eta 0
      • 'optimal': eta = 1.0 / (alpha * (t + t 0)) [default]
      • 'invscaled': eta = eta 0 / pow (t, power_t)
      • power_t=0.25: 存在父类当中
      • 对于一个常数值的学习率来说,可以使用 learning_rate='constant', 并使用 eta 0 来指定学习率。
    • SGDRegressor. coef_: 回归系数
    • SGDRegressor. intercept_: 偏置

两种 API 的调用

波士顿房价预测

流程

  1. 获取数据集
  2. 划分数据集
  3. 特征工程:
    1. 因为要进行损失函数的计算,所以需要进行无量纲化的处理(标准化)
  4. 预估器
    1. fit ()——>模型
    2. coef_intercept
  5. 模型评估

代码:

Python
from statistics import LinearRegression  
from sklearn.datasets import fetch_california_housing  
from sklearn.linear_model import SGDClassifier, SGDRegressor  
from sklearn.model_selection import train_test_split  
from sklearn.preprocessing import StandardScaler  
from sklearn.linear_model import LinearRegression, SGDRegressor  

def linear1():  
    """  
    正规方程的优化方法对波士顿房价进行预测  
    :return:    """    # 1.获取数据  
    boston = fetch_california_housing()  
    print("特征数量:\n",boston.data.shape)  
    # 2.划分数据集  
    x_train,x_test,y_train,y_test=train_test_split(boston.data,boston.target,random_state=22)  

    # 3.特征工程  
    transfer=StandardScaler()  
    x_train=transfer.fit_transform(x_train)  
    x_test=transfer.transform(x_test)  
    # 4.预估器  
    estimator=LinearRegression()  
    estimator.fit(x_train,y_train)  

    # 5.得出模型  
    print("正规方程权重系数为:\n",estimator.coef_)  
    print("正规方程偏置为\n",estimator.intercept_)  
    # 6.模型评估  
    return None  

def linear2():  
    """  
    梯度下降的优化方法对波士顿房价进行预测  
    :return:    """    # 1.获取数据  
    boston = fetch_california_housing()  
    # 2.划分数据集  
    x_train,x_test,y_train,y_test=train_test_split(boston.data,boston.target,random_state=22)  

    # 3.特征工程  
    transfer=StandardScaler()  
    x_train=transfer.fit_transform(x_train)  
    x_test=transfer.transform(x_test)  
    # 4.预估器  
    estimator=SGDRegressor()  
    estimator.fit(x_train,y_train)  

    # 5.得出模型  
    print("梯度下降权重系数为:\n",estimator.coef_)  
    print("梯度下降偏置为\n",estimator.intercept_)  
    # 6.模型评估  
    return None  
# 1.正规方程  
linear1()  
# 2. 梯度下降  
linear2()

boston.data 这种用法好像只有 sklearn 内置的数据集才能使用(因为内置的自己就划分了哪些是特征值,哪些是目标值)

模型的评估

均方误差评价机制:

\[ MSE=\frac{1}{m}\sum_{i=1}^m\left(y^i-\bar{y}\right)^2 \]

实际上就是每一个样本的预测值减去平均值的平方的平均(方差)
哪一个模型的均方误差小,哪个就好

  • sklearn. metrics. mean_squared_error (y_true, y_pred)
    • 均方误差回归损失
    • y_true: 真实值
    • y_pred: 预测值
    • return: 浮点数结果

头文件:from sklearn.metrics import mean_squared_error

Python
1
2
3
4
y_predict=estimator.predict(x_test)  
print("预测房价:\n",y_predict)  
error=mean_squared_error(y_test,y_predict)  
print("正规方程的均方误差为:\n",error)

梯度下降可以条件的参数比较多!
estimator=SGDRegressor(learning_rate="constant",eta0=0.000001,max_iter=100000)
前面是 eta 0 为初始学习率(也就是步长,每一次迭代变化的幅度)
max_iter 为迭代的次数
learning_rate="constant"代表学习率不变

  • <100 K 不用梯度下降,数据量足够多才使用 SGD
  • 小数据使用岭回归(一般不使用 LinearRegression()

梯度下降优化器

  1. GD
    最原始的梯度下降,需要计算所有样本的值才能得出梯度,计算量大
  2. SGD
    随机梯度下降,在一次迭代时只考虑一个训练样本
  3. SAG
    计算平均梯度

欠拟合与过拟合

什么是欠拟合与过拟合

在训练数据的时候,模型在训练集上表现很好,但是在测试集上有问题,这种就是出现了过拟合现象

拟合

欠拟合:
天鹅的图片,但是识别到的特征是有翅膀和嘴巴长,识别到的特征太小了,很多的其他都归到了天鹅身上
在训练集和测试集上都不好(模型过于简单)
过拟合:
过多了
在训练集上好,但是在测试集上效果不好(模型过于复杂)

解决方法

  • 欠拟合:
    • 增加数据的特征数量
  • 过拟合
    • 原因:原始特征过多,存在一些嘈杂的特征,模型过于复杂,尝试去兼顾每一个测试数据点
    • 解决方法:正则化


中间的最好,左边为欠拟合,右边为过拟合

过拟合的解决

\[ \theta_0+\theta_1x+\theta_2x^2+\theta_3x^3+\theta_4x^4 \]

尽量减小高次项的系数
解决方法:正则化

正则化类型

L 2 正则化

  • 作用:使得其中一些 w (系数) 很小,接近于 0,减小某个特征的影响
  • 加入损失函数:

    \[ J(w)=\frac{1}{2m}\sum_{i=1}^{m}(h_{w}(x_{i})-y_{i})^{2}+\lambda\sum_{j=1}^{n}w_{j}^{2} \]

    L 2 正则化更加常用
    损失函数+ \(\lambda\) 惩罚项
    Ridge——岭回归

L 1 正则化

损失函数+ \(\lambda\) 惩罚项,但是后面相乘的变成了 w(权重系数) 的绝对值
使得一些 w 直接为 0,相当于删除了一些项,而 L 2 是减小影响

线性回归的改进——岭回归

是一种加上正则化的线性回归

带有 L 2 正则化的线性回归——岭回归

API 调用

  • sklearn.linear_model.Ridge(alpha=1.0, fit_intercept=True, solver="auto", normalize=False)

    • 具有L2正则化的线性回归
    • alpha: 正则化力度,也叫 λ(就是上面的 \(\lambda\)
      • λ取值:0-1 1-10
    • solver: 会根据数据自动选择优化方法
      • sag: 如果数据集、特征都比较大,选择该随机梯度下降优化
    • normalize: 数据是否进行标准化(就是相当于之前的标准化
      • normalize=False: 可以在fit之前调用preprocessing.StandardScaler标准化数据
    • Ridge.coef_: 回归权重(看模型的结果)
    • Ridge.intercept_: 回归偏置(结果)
  • 正则化力度越大,权重系数越小

  • 正则化力度越小,权重系数会越大

用法

  • 头文件:
    from sklearn.linear_model import LinearRegression, SGDRegressor,Ridge
  • 总的代码:

    Python
    # 3.特征工程  
    transfer=StandardScaler()  
    x_train=transfer.fit_transform(x_train)  
    x_test=transfer.transform(x_test)  
    # 4.预估器  
    estimator=Ridge(max_iter=100,alpha=0.5)  
    estimator.fit(x_train,y_train)  
    
    # 5.得出模型  
    print("岭回归权重系数为:\n",estimator.coef_)  
    print("岭回归偏置为\n",estimator.intercept_)  
    # 6.模型评估  
    y_predict=estimator.predict(x_test)  
    print("预测房价:\n",y_predict)  
    error=mean_squared_error(y_test,y_predict)  
    print("岭回归的均方误差为:\n",error)  
    return None
    

分类算法-逻辑回归与二分类

逻辑回归是一种分类算法

应用场景

  • 广告点击率
  • 是否为垃圾邮件
  • 是否患病
  • 金融诈骗
  • 虚假账号

上面的例子都是二分类的问题 (两个类别之间的
所以说逻辑回归是解决二分类问题的利器

逻辑回归的原理

输入

\[ h(w)=w_{1}x_{1}+w_{2}x_{2}+w_{3}x_{3}…+b \]

可见逻辑回归的输入就是线性回归的结果(输出)

激活函数

  • sigmoid 函数
\[ g(\theta^Tx)=\frac{1}{1+e^{-\theta^Tx}} \]
  • 分析
    • 回归的结果输入 sigmoid 函数中
    • 输出结果为[0,1]的概率值,一般默认0.5 为阈值,小于是某个类比,大于是另一个

总结:将线性回归的输出映射到 sigmoid 函数上,进行分类

假设函数/线性模型

  • 损失函数
    (y_predict-y_ture) 平方和/总数
    逻辑回归真实值是否属于某个示例
  • 对数似然损失函数

    \[ \left.cost(h_\theta(x),y)=\left\{\begin{array}{ll}-log(h_\theta(x))&\mathrm{if~y=1}\\-log(1- h_\theta(x))&\mathrm{if~y=0}\end{array}\right.\right. \]

    因为我们现在的 y 的值为 1,0(分类),所以需要有新的损失函数(就是预测的误差)\(h_\theta(x)\) 为预测的概率值,最后算出来的值就是误差
    等价的表述:(就是把上面的分段函数写成一个的形式)

    \[ cost(h_\theta(x),y)=\sum_{i=1}^m-y_ilog(h_\theta(x))-(1-y_i)log(1-h_\theta(x)) \]
  • 过程如图:

    由线性的结果(系数的值),将输入带入,计算出回归的值,之后带入 sigmoid 中,计算逻辑回归结果,与阈值 0.5 比较,得出真实的结果
    上面的图中,预测的结果为 0,1,0,1,1,真实的结果是 1,0,1,0,1
    所以带入上面的损失计算公式进行计算

    \[ -[1\log(0.4)+(1-0)\log(1-0.68)+1\log(0.41)+(1-0)\log(1-0.55)+1\log(0.71)] \]

    我们总的损失就计算出来了


有了损失函数之后就要进行优化:
调整 w(参数),使得结果越来越接近(损失减小)
使用梯度下降的方法进行优化

逻辑回归API 调用

  • sklearn.linear_model.LogisticRegression(solver='liblinear', penalty='l2', C=1.0)
    • solver: 优化求解方式(默认开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数)
      • sag: 根据数据集自动选择,随机平均梯度下降
    • penalty: 正则化的种类
    • C: 正则化力度

可以实现 SAG

案例:癌症分类预测的案例

数据集:https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data
names:https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.names

流程

  1. 获取数据
    1. 读取的时候加上 names
  2. 数据处理(因为不是使用 sklearn 的数据了)
    1. 处理缺失值
  3. 数据集划分
  4. 特征工程
    1. 无量纲化(标准化)
  5. 逻辑回归预估器
  6. 模型评估

代码:

Python
1
2
3
4
# 读取数据
path="https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"
names = ['Sample code number', 'Clump Thickness', 'Uniformity of Cell Size', 'Uniformity of Cell Shape','Marginal Adhesion', 'Single Epithelial Cell Size', 'Bare Nuclei', 'Bland Chromatin','Normal Nucleoli', 'Mitoses', 'Class']
data=pd.read_csv(path,names=names)# 因为之前的数据是没有名字的

Python
1
2
3
4
5
6
# 缺失值处理
    # 将?替换为np.nan
data=data.replace(to_replace="?",value=np.nan)
    # 删除缺失的样本
data.dropna(inplace=True)
data.isnull().any()# 不存在缺失值
Python
x=data.iloc[:,1:-1]
y=data["Class"]
Python
1
2
3
4
5
6
7
# 模型评估
y_predict=estimator.predict(x_test)
print("y_predict:\n",y_predict)
print("直接比较的准确率:\n",y_test==y_predict)
    # 方法二:计算准确率
score=estimator.score(x_test,y_test)
print("准确率为\n",score)

我们现在要引入一些新的评估方法

分类的评估方法

1 精确率和召回率

预测与正确之间的关系可能有

预测结果
正例 假例
真实结果 正例 真正例 TP 伪反FN
假例 伪正FP 正反TN
  • 精确率(Precision):预测结果为正例中真实为正例的比例
  • 召回率(Recall):真实为正例中,预测结果也是正例的比例,看查的全不全
  • F 1_score: 保证了模型的稳健性

    \[ F1=\frac{2TP}{2TP+FN+FP}=\frac{2\cdot Precision\cdot Recall}{Precision+Recall} \]

在癌症中,恶性是正例,所以召回率就非常重要

API
- sklearn.metrics.classification_report(y_true, y_pred, labels=[], target_names=None) - y_true: 真实目标值 - y_pred: 估计器预测目标值 - labels: 指定类别对应的数字 - target_names: 目标类别名称 - return: 每个类别精确率与召回率(该函数的返回值)

这个在均方误差中也是出现过的

步骤

  1. 头文件:from sklearn.metrics import classification_report
  2. 设定:report=classification_report(y_test,y_predict,labels=[2,4],target_names=["良性","恶性"])
  3. 最后的结果:print(report)
    precision recall f1-score support
    Text Only
    1
    2
      良性       0.98      0.98      0.98       111
      恶性       0.97      0.97      0.97        60
    

总共的样本:99 个是癌症,1 个不是癌症,模型全部预测为正例
此时的准确率为 99%,召回率为 100%,精确率为 99%,F 1_score:99.497%
但是这种模型是不负责任的,怎么办?(样本不均衡)


ROC 曲线和 AUC 指标
AUC 越接近 1 越好

TPR 和 FPR

  • TPR = TP / (TP + FN)(召回率)
    • 所有真实类别为1的样本中,预测类别为1的比例
  • FPR = FP / (FP + TN)
    • 所有真实类别为0的样本中,预测类别为1的比例

ROC 曲线


横坐标是 FPR,纵坐标是 TPR, 两者相等时,表示的含义是无论真实的类别是 1 还是 0,分类器预测为 1 的概率是相等的(也就是瞎猜,不按真实的情况)啊,此时的 AUC 为 0.5(就是曲线与右部分围成的面积)

!!! tip "指标"
- 最小值为 0.5,最大值为 1,取值越高越好
- 小于 0.5 的时候就反着预测即可

API
- from sklearn.metrics import roc_auc_score - sklearn.metrics.roc_auc_score(y_true, y_score) - 计算ROC曲线面积,即AUC值 - y_true: 每个样本的真实类别,必须为0(反例).1(正例)标记 - y_score: 预测得分,可以是正类的估计概率、置信值或者分类器方法的返回值

Python
1
2
3
4
5
6
# y_true: 每个样本的真实类别,**必须为0(反例).1(正例)标记**
# 所以将y_test转换
y_true=np.where(y_test>3,1,0)

from sklearn.metrics import roc_auc_score
roc_auc_score(y_true,y_predict)

非常适合评价样本不均衡时的

模型的保存和加载

sklearn 中的

  • from sklearn.externals import joblib
    • 保存: joblib.dump(rf, 'test.pkl')
    • 加载: estimator = joblib.load('test.pkl')

保存线性回归的模型

Python
1
2
3
4
5
# 4.预估器  
estimator=Ridge(max_iter=100,alpha=0.5)  
estimator.fit(x_train,y_train)  
# 保存模型  
joblib.dump(estimator, 'my.pkl')  
Python
# 加载模型  
estimator = joblib.load('my.pkl')  

无监督学习-K-means 算法

什么是无监督学习

看目标值:没有目标值的话就是无监督学习

包含的算法

  • 聚类:
    • K-means(K 均值聚类)
  • 降维
    • PCA

K-means 原理


实现上面将数据分为三类

步骤

  1. 随机设置 k 个特征空间内的点作为初始的聚类中心
    K:超参数
    1. 看需求(分为几类)
    2. 网格搜索,调节超参数
  2. 对于其他的每个点计算到 k 个中心的距离,未知的点选择最近的聚类中心作为标记类别
  3. 接着对着标记的聚类,重新计算每个聚类的新中心点(平均值)
  4. 如果计算得出的新中心点与原中心点一样,那么结束,否则重新进行第二步的步骤

中心点是怎么求的
\(A(a1,b1,c1)\) \({B}(\) a2, b2, c2)
\({Z}(\)a26, b26, c26)
中心点(a平均,b平均,c平均)

API

  • sklearn.cluster.KMeans(n_clusters=8,init='k-means++')
    • k-means聚类
    • n_clusters:开始的聚类中心数量 (就是 K 值)
    • init:初始化方法,默认为'k-means++'
    • labels_:默认标记的类型,可以和真实值比较(不是值比较)(可以查看标记的类型)

案例:Instacart Market 用户聚类

分为三种(这个数据已经处理了)

流程分析

  1. 预估器流程
  2. 看结果
  3. 模型评估
Python
1
2
3
4
5
6
# 预估器流程
from sklearn.cluster import KMeans
estimator=KMeans(n_clusters=3)
estimator.fit(data_new)
y_predict=estimator.predict(data_new)
y_predict[:300]

Kmeans 性能评估的指标

轮廓系数

\[ sc_i=\frac{b_{i-}a_i}{\max(b_i,a_i)} \]

对于每个点 i,为已经聚类数据中的样本,b_i 为 i 到其他的族群的所有样本距离的最小值,a_i 为到本身蔟的距离的平均值,最终计算出所有样本点的轮廓系数平均值

轮廓系数分析

使得外部的距离(b_i)大,内部距离小 (a_i)
取极限的情况时,分子为 b_i,分母为 a_i,此时的系数为 1,时最好的情况
最差的情况为-1

结论

介于[-1,1],越接近 1 越好,越接近-1 越差

  • sklearn.metrics.silhouette_score(X, labels)
    • 计算所有样本的平均轮廓系数
    • X: 特征值
    • labels: 被聚类标记的目标值
Python
silhouette_score(data_new,y_predict)

聚类的总结

  • 特点:迭代算法,直观易懂
  • 缺点:容易收敛到局部最优解(开始的初始中心点挨在一起了)(可以使用多次聚类解决)

聚类一般在分类之前,我们还是要分类的(最终的目标)
就是给分类提供一个目标值

完结:前面有数据挖掘,后面有深度学习

猫咪

总结


💐💐💐