机器学习课程

机器学习概述

什么是机器学习

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

机器学习算法分类

监督学习

目标值:类别—分类问题

KNN、贝叶斯分类、决策树与随机森林、逻辑回归

目标值:连续型数据—回归问题

线性回归、岭回归

无监督学习

目标值:无

聚类K-means

img

机器学习开发流程

1)获取数据

2)数据处理

3)特征工程

4)机器学习算法训练—模型

5)模型评估

6)应用

特征工程

数据集

数据———数据集的构成———特征值 + 目标值

可用数据集

Kaggle特点:1、大数据竞赛平台 2、80万科学家 3、真实数据 4、数据量巨大

UCI特点:1、收录了360个数据集 2、覆盖科学、生活、经济等领域 3、数据量几十万

scikit-learn特点:1、数据量较小 2、方便学习

网址:

Kaggle网址:https://www.kaggle.com/datasets

UCI数据集网址: http://archive.ics.uci.edu/ml/

scikit-learn网址:http://scikit-learn.org/stable/datasets/index.html#datasets

sklearn数据集

load_*小规模的数据集

fetch_*大规模的数据集

Bunch类型

数据集划分—model_selection.train_test_split()

  • 训练数据:用于训练,构建模型

  • 测试数据:在模型检验时使用,用于评估模型是否有效

特征工程介绍

特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,从而提高了对未知数据的模型准确性。

sklearn 特征工程

Scikit-learn包含的内容:分类、聚类、回归、特征工程、模型选择和调优。

pandas 数据清洗、数据处理

特征处理是特征工程的核心部分,包括特征提取数据预处理特征选择特征降维等。

特征提取

特征提取包括将任意数据(如文本或图像)转换为可用于机器学习的数字特征。
注:特征值化是为了计算机更好的去理解数据

包:sklearn.feature_extraction

字典特征提取

  • 应用DictVectorizer实现对类别特征进行数值化、离散化

    sklearn.feature_extraction.DictVectorizer(sparse=True,…)
    DictVectorizer.fit_transform(X) X:字典或者包含字典的迭代器返回值:返回sparse矩阵
    DictVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
    DictVectorizer.get_feature_names() 返回类别名称
    应用:

代码:

1
2
3
4
5
6
7
8
9
10
#对字典类型的数据进行特征抽取
from sklearn.feature_extraction import DictVectorizer
data = [{'city': '北京','temperature':100}, {'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]
# 1、实例化一个转换器类
transfer = DictVectorizer(sparse=False)
# 2、调用fit_transform
data = transfer.fit_transform(data)
print("返回的结果:\n", data)
# 打印特征名字
print("特征名字:\n", transfer.get_feature_names())

输出结果:

1
2
3
4
5
6
返回的结果:
[[ 0. 1. 0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 30.]]
特征名字:
['city=上海', 'city=北京', 'city=深圳', 'temperature']

文本特征提取

  • 独热编码(One-HotEncoding)

  • 应用CountVectorizer实现对文本特征进行数值化

  • 应用TfidfVectorizer(TF-IDF)实现对文本特征进行数值化

    sklearn.feature_extraction.text.CountVectorizer(stop_words=[])

    返回词频矩阵
    CountVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
    CountVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格
    CountVectorizer.get_feature_names() 返回值:单词列表
    sklearn.feature_extraction.text.TfidfVectorizer

    • TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
    • TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
1
2
3
4
5
6
7
8
from sklearn.feature_extraction.text import TfidfVectorizer
# 对于文本数据,进行特征抽取
tf = TfidfVectorizer()
x_train = tf.fit_transform(x_train)#20类新闻分类数据集
#这里打印出来的列表是:训练集当中的所有不同词的组成的一个列表
print(tf.get_feature_names())
# print(x_train.toarray())
x_test = tf.transform(x_test) # 不需要fit_transform
  • 应用

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
import jieba
def cut_word(text):
# 用jieba对中文字符串进行分词
text = " ".join(list(jieba.cut(text)))
return text
#对中文进行特征抽取
data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。",
"life is short,i like like python", "life is too long,i dislike python"]
# 将原始数据转换成分好词的形式
text_list = []
for sent in data:
text_list.append(cut_word(sent))
print(text_list)
# 1、实例化一个转换器类
transfer = CountVectorizer()
#transfer = TfidfVectorizer()
# 2、调用fit_transform
data = transfer.fit_transform(text_list)
print("文本特征抽取的结果:\n", data.toarray())
print("返回特征名字:\n", transfer.get_feature_names())

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
['一种 还是 一种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。', 'life   is   short , i   like   like   python', 'life   is   too   long , i   dislike   python']
文本特征抽取的结果:
[[0 0 0 0 0 0 0 0 2 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1
0 0 0 1 1 0 0 1 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0
2 0 0 0 0 0 1 0 1]
[0 0 0 0 0 0 0 0 1 1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0
0 2 1 0 0 1 0 0 0]
[0 1 1 2 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0]
[1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0]]
返回特征名字:
['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too', '一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

图像特征提取(深度学习将介绍)

数据预处理

去除唯一属性

唯一属性通常是一些id属性,这些属性并不能刻画样本自身的分布规律,所以简单地删除这些属性即可。

处理缺失值

缺失值处理的三种方法:直接使用含有缺失值的特征;删除含有缺失值的特征(该方法在包含缺失值的属性含有大量缺失值而仅仅包含极少量有效值时是有效的);缺失值补全。

常见的缺失值补全方法:均值插补、同类均值插补、建模预测、高维映射、多重插补、极大似然估计、压缩感知和矩阵补全。

(1)均值插补

如果样本属性的距离是可度量的,则使用该属性有效值的平均值来插补缺失的值;

如果的距离是不可度量的,则使用该属性有效值的众数来插补缺失的值。如果使用众数插补,出现数据倾斜会造成什么影响?

(2)同类均值插补

首先将样本进行分类,然后以该类中样本的均值来插补缺失值。

(3)建模预测

将缺失的属性作为预测目标来预测,将数据集按照是否含有特定属性的缺失值分为两类,利用现有的机器学习算法对待预测数据集的缺失值进行预测。

该方法的根本的缺陷是如果其他属性和缺失属性无关,则预测的结果毫无意义;但是若预测结果相当准确,则说明这个缺失属性是没必要纳入数据集中的;一般的情况是介于两者之间。

(4)高维映射

将属性映射到高维空间,采用独热码编码(one-hot)技术。将包含K个离散取值范围的属性值扩展为K+1个属性值,若该属性值缺失,则扩展后的第K+1个属性值置为1。

这种做法是最精确的做法,保留了所有的信息,也未添加任何额外信息,若预处理时把所有的变量都这样处理,会大大增加数据的维度。这样做的好处是完整保留了原始数据的全部信息、不用考虑缺失值;缺点是计算量大大提升,且只有在样本量非常大的时候效果才好。

(5)多重插补(MultipleImputation,MI)

多重插补认为待插补的值是随机的,实践上通常是估计出待插补的值,再加上不同的噪声,形成多组可选插补值,根据某种选择依据,选取最合适的插补值。

(6)压缩感知和矩阵补全

(7)手动插补

插补处理只是将未知值补以我们的主观估计值,不一定完全符合客观事实。在许多情况下,根据对所在领域的理解,手动对缺失值进行插补的效果会更好。

特征编码

(1)标签处理

通常我们会把字符型的标签转换成数值型的

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
df = pd.DataFrame([
['green', 'M', 10.1, 'class1'],
['red', 'L', 13.5, 'class2'],
['blue', 'XL', 15.3, 'class1']])
df.columns = ['color', 'size', 'prize', 'class label']
#标签处理
class_mapping = {label:idx for idx,label in enumerate(set(df['class label']))}
df['class label'] = df['class label'].map(class_mapping)
print(df)
print('-----------------------------------')
size_mapping = {
'XL': 3,
'L': 2,
'M': 1}

df['size'] = df['size'].map(size_mapping)
print(df)

输出结果:

1
2
3
4
5
6
7
8
9
   color size  prize  class label
0 green M 10.1 1
1 red L 13.5 0
2 blue XL 15.3 1
-----------------------------------
color size prize class label
0 green 1 10.1 1
1 red 2 13.5 0
2 blue 3 15.3 1

(2)二值化

二值化的过程是将数值型的属性转换为布尔值的属性,设定一个阈值作为划分属性值为0和1的分隔点。

使用preproccessing库的Binarizer类对数据进行二值化的代码如下:

1
2
3
from sklearn.preprocessing import Binarizer
#二值化,阈值设置为3,返回值为二值化后的数据
Binarizer(threshold=3).fit_transform(X) #X=iris.data(鸢尾花)数据集

(3)scikit DictVectorizer

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pandas as pd
df = pd.DataFrame([
['green', 'M', 10.1, 'class1'],
['red', 'L', 13.5, 'class2'],
['blue', 'XL', 15.3, 'class1']])
df.columns = ['color', 'size', 'prize', 'class label']
print(df)
print('----------------------------------------------------------------------')
#print(df.transpose().to_dict().values())
#print('----------------------------------------------------------------------')
feature = df.iloc[:, :-1]
print(feature)
print('----------------------------------------------------------------------')
# ②对于x转换成字典数据
feature=feature.to_dict(orient="records")
#feature=feature.transpose().to_dict().values() #对所有的数据都做了映射
#使用 DictVectorizer将得到特征的字典
from sklearn.feature_extraction import DictVectorizer
dvec = DictVectorizer(sparse=False)
X = dvec.fit_transform(feature)
print(dvec.get_feature_names())
print('----------------------------------------------------------------------')
print(X)
print('----------------------------------------------------------------------')
#可以调用 get_feature_names 来返回新的列的名字,其中0和1就代表是不是这个属性.
data=pd.DataFrame(X, columns=dvec.get_feature_names())
print(data)

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   color size  prize class label
0 green M 10.1 class1
1 red L 13.5 class2
2 blue XL 15.3 class1
----------------------------------------------------------------------
color size prize
0 green M 10.1
1 red L 13.5
2 blue XL 15.3
----------------------------------------------------------------------
['color=blue', 'color=green', 'color=red', 'prize', 'size=L', 'size=M', 'size=XL']
----------------------------------------------------------------------
[[ 0. 1. 0. 10.1 0. 1. 0. ]
[ 0. 0. 1. 13.5 1. 0. 0. ]
[ 1. 0. 0. 15.3 0. 0. 1. ]]
----------------------------------------------------------------------
color=blue color=green color=red prize size=L size=M size=XL
0 0.0 1.0 0.0 10.1 0.0 1.0 0.0
1 0.0 0.0 1.0 13.5 1.0 0.0 0.0
2 1.0 0.0 0.0 15.3 0.0 0.0 1.0

(4)独热编码(One-HotEncoding)

独热编码采用N位状态寄存器来对N个可能的取值进行编码,每个状态都由独立的寄存器来表示,并且在任意时刻只有其中一位有效。

独热编码的优点:能够处理非数值属性;在一定程度上扩充了特征;编码后的属性是稀疏的,存在大量的零元分量。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
df = pd.DataFrame([
['green', 'M', 10.1, 'class1'],
['red', 'L', 13.5, 'class2'],
['blue', 'XL', 15.3, 'class1']])
df.columns = ['color', 'size', 'prize', 'class label']
#OneHotEncoder 必须使用整数作为输入,所以得先使用scikit LabelEncoder处理一下
from sklearn.preprocessing import LabelEncoder
class_le = LabelEncoder()
df['class label'] = class_le.fit_transform(df['class label'])
print(df)
print('-----------------------------------')
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(sparse=False)
X = ohe.fit_transform(df[['color']].values)
print(X)

输出结果:

1
2
3
4
5
6
7
8
   color size  prize  class label
0 green M 10.1 0
1 red L 13.5 1
2 blue XL 15.3 0
-----------------------------------
[[0. 1. 0.]
[0. 0. 1.]
[1. 0. 0.]]

注:Pandas库中同样有类似的操作,使用get_dummies也可以得到相应的特征

(5)pandas get_dummies

代码:

1
2
3
4
5
6
7
8
import pandas as pd
df = pd.DataFrame([
['green',10.1],
['red', 13.5],
['blue',15.3]])
df.columns = ['color', 'prize']
df=pd.get_dummies(df)
print(df)

输出结果:

1
2
3
4
   prize  color_blue  color_green  color_red
0 10.1 0 1 0
1 13.5 0 0 1
2 15.3 1 0 0

无量纲化、正则化

无量纲化

数据标准化是将样本的属性缩放到某个指定的范围。

标准化:基于原始数据的均值(mean)和标准差(standarddeviation)进行数据的标准化。

要求 均值$\mu = 0$ 和标准差 $\sigma = 1$

公式表达为:

使用preproccessing库的StandardScaler类对数据进行标准化的代码如下:

1
2
3
4
from sklearn.preprocessing import StandardScaler 
#标准化,返回值为标准化后的数据
ss=StandardScaler()
X1=ss.fit_transform(X) #X=iris.data(鸢尾花)数据集

归一化:处理后的所有特征的值都会被压缩到 0到1区间上.这样做还可以抑制离群值对结果的影响.

公式表达为:

使用preproccessing库的MinMaxScaler类对数据进行区间缩放的代码如下:

1
2
3
4
from sklearn.preprocessing import MinMaxScaler
#区间缩放,返回值为缩放到[0, 1]区间的数据
mms=MinMaxScaler()
X2=mms.fit_transform(X) #X=iris.data(鸢尾花)数据集
正则化

正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。

该方法主要应用于文本分类和聚类中。

1
2
3
from sklearn.preprocessing import Normalizer
ss=Normalizer()
X3=ss.fit_transform(X) #X=iris.data(鸢尾花)数据集
标准化与正则化的区别

简单来说,标准化是依照特征矩阵的列处理数据,其通过求z-score的方法,将样本的特征值转换到同一量纲下。正则化是依照特征矩阵的行处理数据,其目的在于样本向量在点乘运算或其他核函数计算相似性时,拥有统一的标准,也就是说都转化为“单位向量”。

特征选择

特征选择:数据中包含冗余或相关变量(或特征、属性、指标),旨在从原有特征中找出主要特征。

包:sklearn.feature_selection

当数据预处理完成后,我们需要选择有意义的特征输入机器学习的算法和模型进行训练。通常来说,从两个方面考虑来选择特征:

  • 特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用
  • 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。除移除低方差法外,本文介绍的其他方法均从相关性考虑。

根据特征选择的形式又可以将特征选择方法分为3种:

Filter

Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。

方差选择法:低方差特征过滤

代码:

1
2
3
4
5
from sklearn.feature_selection import VarianceThreshold
X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
X1=sel.fit_transform(X)
print(X1)

输出结果:

1
2
3
4
5
6
[[0 1]
[1 0]
[0 0]
[1 1]
[1 0]
[1 1]]

果然, VarianceThreshold 移除了第一列特征,第一列中特征值为0的概率达到了5/6.

相关系数:特征与特征之间的相关程度(与目标相关性高的特征,应当优选选择

  • 对于分类问题(y离散),可采用:

    卡方检验f_classif, mutual_info_classif互信息

  • 对于回归问题(y连续),可采用:
    皮尔森相关系数f_regression, mutual_info_regression,最大信息系数

    卡方(Chi2)检验

    ​ 经典的卡方检验是检验定性自变量对定性因变量的相关性。假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距,构建统计量:

    假设有两个分类变量X和Y,它们的值域分别为{x1, x2}和{y1, y2},其样本频数列联表为:

经典的卡方检验是检验定性自变量对定性因变量的相关性,针对分类问题。比如,我们可以对样本进行一次chi2测试来选择最佳的两项特征:

代码:

1
2
3
4
5
6
7
8
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
iris = load_iris()
X, y = iris.data, iris.target
print(X.shape)
X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
print(X_new.shape)

输出结果:

1
2
(150, 4)
(150, 2)

Pearson相关系数 (Pearson Correlation)

​ 皮尔森相关系数是一种最简单的,能帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性,结果的取值区间为[-1,1],-1表示完全的负相关,+1表示完全的正相关,0表示没有线性相关。

​ Pearson Correlation速度快、易于计算,经常在拿到数据(经过清洗和特征提取之后的)之后第一时间就执行。Scipy的 pearsonr 方法能够同时计算相关系数和p-value.

代码:

1
2
3
4
5
6
7
8
import numpy as np
from scipy.stats import pearsonr
np.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
# pearsonr(x, y)的输入为特征矩阵和目标向量
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))

输出结果:

1
2
3
#输出为二元组(sorce, p-value)的数组
Lower noise (0.7182483686213842, 7.324017312997672e-49)
Higher noise (0.05796429207933815, 0.31700993885325246)

这个例子中,我们比较了变量在加入噪音之前和之后的差异。当噪音比较小的时候,相关性很强,p-value很低。

实例分析:股票的财务指标相关性计算

分析

  • 两两特征之间进行相关性计算

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    import numpy as np
    from scipy.stats import pearsonr
    import pandas as pd
    data = pd.read_csv("factor_returns.csv")
    factor = ['pe_ratio', 'pb_ratio', 'market_cap', 'return_on_asset_net_profit', 'du_return_on_equity', 'ev','earnings_per_share', 'revenue', 'total_expense']
    for i in range(len(factor)):
    for j in range(i, len(factor) - 1):
    print("指标%s与指标%s之间的相关性大小为%f" % (factor[i], factor[j + 1], pearsonr(data[factor[i]], data[factor[j + 1]])[0]))

    输出结果:(展示部分数据结果)

    1
    2
    3
    4
    5
    6
    7
    指标pe_ratio与指标pb_ratio之间的相关性大小为-0.004389
    指标pe_ratio与指标market_cap之间的相关性大小为-0.068861
    ………………………………………………………………………………………………………………………………………………………………
    指标return_on_asset_net_profit与指标du_return_on_equity之间的相关性大小为0.818697
    指标return_on_asset_net_profit与指标ev之间的相关性大小为-0.101225
    ………………………………………………………………………………………………………………………………………………………………
    指标revenue与指标total_expense之间的相关性大小为0.995845

    从中我们得出

  • 指标revenue与指标total_expense之间的相关性大小为0.995845

  • 指标return_on_asset_net_profit与指标du_return_on_equity之间的相关性大小为0.818697

    我们也可以通过画图来观察结果

    代码:

    1
    2
    3
    4
    import matplotlib.pyplot as plt
    plt.figure(figsize=(20, 8), dpi=100)
    plt.scatter(data['revenue'], data['total_expense'])
    plt.show()

    Figure_1

    注:特征与特征之间相关性很高:1)选取其中一个;2)权重加权求和;3)主成分分析

    Scikit-learn提供的 f_regrssion 方法能够批量计算特征的f_score和p-value,非常方便,参考sklearn的 pipeline

    Pearson相关系数的一个明显缺陷是,作为特征排序机制,他只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应的关系,Pearson相关性也可能会接近0。例如:

    代码:

    1
    2
    x = np.random.uniform(-1, 1, 100000)
    print pearsonr(x, x**2)[0]

    输出结果:

    1
    -0.00230804707612

    更多类似的例子参考 sample plots 。另外,如果仅仅根据相关系数这个值来判断的话,有时候会具有很强的误导性,如 Anscombe’s quartet ,最好把数据可视化出来,以免得出错误的结论。

    互信息和最大信息系数 (Mutual information and maximal information coefficient (MIC)

    经典的互信息(互信息为随机变量X与Y之间的互信息$I(X;Y)$为单个事件之间互信息的数学期望)也是评价定性自变量对定性因变量的相关性的,互信息计算公式如下:

    互信息直接用于特征选择其实不是太方便:

    1、它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;

    2、对于连续变量的计算不是很方便(X和Y都是集合,x,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。

    最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,取值区间在[0,1]。 minepy 提供了MIC功能。

    反过头来看y=x^2这个例子,MIC算出来的互信息值为1(最大的取值)。

    代码:

    1
    2
    3
    4
    5
    6
    import numpy as np
    from minepy import MINE
    m = MINE()
    x = np.random.uniform(-1, 1, 10000)
    m.compute_score(x, x**2)
    print(m.mic())

    输出结果:

    1
    1.0000000000000009

    MIC的统计能力遭到了 一些质疑 ,当零假设不成立时,MIC的统计就会受到影响。在有的数据集上不存在这个问题,但有的数据集上就存在这个问题。

    距离相关系数 (Distance Correlation)

    距离相关系数是为了克服Pearson相关系数的弱点而生的。在$X$和$X^2$这个例子中,即便Pearson相关系数是0,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是0,那么我们就可以说这两个变量是独立的。

    R的 energy 包里提供了距离相关系数的实现,另外这是 Python gist 的实现。

    尽管有 MIC 和 距离相关系数在了,但当变量之间的关系接近线性相关的时候,Pearson相关系数仍然是不可替代的。
    第一,Pearson相关系数计算速度快,这在处理大规模数据的时候很重要。
    第二,Pearson相关系数的取值区间是[-1,1],而MIC和距离相关系数都是[0,1]。这个特点使得Pearson相关系数能够表征更丰富的关系,符号表示关系的正负,绝对值能够表示强度。当然,Pearson相关性有效的前提是两个变量的变化关系是单调的。

    基于模型的特征排序 (Model based ranking)

    这种方法的思路是直接使用你要用的机器学习算法,针对每个单独的特征和响应变量建立预测模型。假如特征和响应变量之间的关系是非线性的,可以用基于树的方法(决策树、随机森林)、或者扩展的线性模型等。基于树的方法比较易于使用,因为他们对非线性关系的建模比较好,并且不需要太多的调试。但要注意过拟合问题,因此树的深度最好不要太大,再就是运用交叉验证

    在波士顿房价数据集上使用sklearn的随机森林回归给出一个单变量选择的例子(这里使用了交叉验证):

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from sklearn.model_selection import cross_val_score, ShuffleSplit
    from sklearn.datasets import load_boston
    from sklearn.ensemble import RandomForestRegressor
    import numpy as np
    # Load boston housing dataset as an example
    boston = load_boston()
    X = boston["data"]
    Y = boston["target"]
    names = boston["feature_names"]
    rf = RandomForestRegressor(n_estimators=20, max_depth=4)
    scores = []
    # 单独采用每个特征进行建模,并进行交叉验证
    for i in range(X.shape[1]):
    score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2", cv=ShuffleSplit(len(X), 3, .3)) # 注意X[:, i]和X[:, i:i+1]的区别
    scores.append((format(np.mean(score), '.3f'), names[i]))
    print(sorted(scores, reverse=True))

    输出结果:

    1
    [('-8.082', 'TAX'), ('-6.871', 'CHAS'), ('-6.420', 'RM'), ('-6.315', 'DIS'), ('-4.833', 'INDUS'), ('-4.816', 'AGE'), ('-4.742', 'LSTAT'), ('-4.638', 'RAD'), ('-3.411', 'NOX'), ('-3.123', 'CRIM'), ('-26.603', 'PTRATIO'), ('-12.284', 'B'), ('-1.995', 'ZN')]

Wrapper

Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。

主要方法有:recursive feature elimination algorithm(递归特征消除算法)

Embedded

Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。比如,Lasso和RF(随机森林)都有各自的特征选择方法。

注:使用SelectFromModel选择特征

1
from sklearn.feature_selection import SelectFromMode

特征降维

二维数组 此处的降维:降低特征的个数 效果:特征与特征之间不相关

降维是指在某种限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程。

当特征选择完成后,可以直接训练模型了,但是可能由于特征矩阵过大,导致计算量大,训练时间长的问题,因此降低特征矩阵维度也是必不可少的。常见的降维方法:主成分分析法(PCA)和线性判别分析(LDA),线性判别分析本身也是一个分类模型。PCA和LDA有很多的相似点,其本质是要将原始的样本映射到维度更低的样本空间中,但是PCA和LDA的映射目标不一样:PCA是为了让映射后的样本具有最大的发散性;而LDA是为了让映射后的样本有最好的分类性能。所以说PCA是一种无监督的降维方法,而LDA是一种有监督的降维方法。

主成分分析法(PCA)

基本思想:构造原变量的一系列线性组合形成几个综合指标,以去除数据的相关性,并使低维数据最大程度保持原始高维数据的方差信息。

主成分个数的确定:

  1. 贡献率:第i个主成分的方差在全部方差中所占比重,反映第i个主成分所提取的总信息的份额。
  2. 累计贡献率:前k个主成分在全部方差中所占比重
  3. 主成分个数的确定:累计贡献率>0.85

相关系数矩阵or协方差阵?
当涉及变量的量纲不同或取值范围相差较大的指标时,应考虑从相关系数矩阵出发进行主成分分析;(相关系数矩阵消除了量纲的影响。)对同度量或取值范围相差不大的数据,从协方差阵出发。

使用decomposition库的PCA类选择特征的代码如下:

1
2
3
4
from sklearn.decomposition import PCA
#主成分分析法,返回降维后的数据
#参数n_components为主成分数目
PCA(n_components=2).fit_transform(X) #X=iris.data(鸢尾花)数据集

n_components:

  • 小数:表示保留百分之多少的信息
  • 整数:减少到多少特征

线性判别分析法(LDA)

至多能把C类数据降维到C-1维子空间

使用lda库的LDA类选择特征的代码如下:

1
2
3
4
from sklearn.lda import LDA
#线性判别分析法,返回降维后的数据
#参数n_components为降维后的维数
LDA(n_components=2).fit_transform(X,Y) #X=iris.data,Y= iris.target(鸢尾花)数据集

小结

2

分类算法

分类问题:目标值—类别

sklearn转换器和估计器

转换器

1.实例化 (实例化的是一个转换器类(Transformer))
2 调用fit_transform(对于文档建立分类词频矩阵,不能同时调用)
标准化:
(x - mean) / std
fit_transform()
fit() #计算 每一列的平均值、标准差
transform() # (x - mean) / std进行最终的转换

估计器

sklearn机器学习算法的实现

1、用于分类的估计器:

  • sklearn.neighbors k-近邻算法
  • sklearn.naive_bayes 贝叶斯
  • sklearn.linear_model.LogisticRegression 逻辑回归
  • sklearn.tree 决策树与随机森林

2、用于回归的估计器:

  • sklearn.linear_model.LinearRegression 线性回归
  • sklearn.linear_model.Ridge 岭回归

3、用于无监督学习的估计器

  • sklearn.cluster.KMeans 聚类
估计器工作流程

1、实例化一个estimator

2、estimator.fit(x_train, y_train) 计算
—— 调用完毕,模型生成

3 模型评估:
1)直接比对真实值和预测值
y_predict = estimator.predict(x_test)
y_test y_predict
2)计算准确率
accuracy = estimator.score(x_test, y_test)

K-近邻算法

K-近邻算法(KNN)

K-近邻算法(KNN)理论/原理:“物以类聚,人以群分”

相同/近似样本在样本空间中是比较接近的,所以可以使用和当前样本比较近的其他样本的目标属性值作为当前样本的预测值。

k-近邻算法的工作机制很简单:

给定测试样本,基于某种距离度量(一般使用欧几里德距离)找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。

如何确定谁是邻居?

计算距离:

距离公式:
欧氏距离:
曼哈顿距离—绝对值距离
明可夫斯基距离:欧氏距离和曼哈顿距离的推广 metric_params=None

123

图中红线代表曼哈顿距离,绿线代表欧氏距离,也就是直线距离,而蓝线黄线代表等价的曼哈顿距离。

电影类型分析

假设我们有现在几部电影

电影类型分析

其中? 号电影不知道类别,如何去预测?我们可以利用K近邻算法的思想

电影距离计算

k = 1 ——>最近距离18.7——>电影为爱情片——>预测?号电影为爱情片
k = 2 ——>最近距离18.7和19.2——两部电影都是爱情片——预测?号电影为爱情片
……
k = 6——> 六部电影爱情片和动作片一样多——>无法确定
k = 7 ——>若4部动作片,3部爱情片——>预测?号电影为动作片,但实际电影为爱情片

如果取的最近的电影数量不一样?会是什么结果?
k 值取得过小,容易受到异常点的影响
k 值取得过大,样本不均衡的影响

K-近邻算法API

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,weights=’uniform’,algorithm=’auto’,
leaf_size=30,p=2,metric=’minkowski’,metric_params=None,n_jobs=None,**kwargs)

  • 邻居数k: n_neighbors:int,可选(默认= 5)
  • 权重weights: weights = ‘uniform’ weights = ‘distance’
  • 距离度量: p=1距离度量采用曼哈顿距离;p=2距离度量采用欧氏距离

  • algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’},可选用于计算最近邻居的算法:‘ball_tree’将会使用 BallTree,‘kd_tree’将使用 KDTree。‘auto’将尝试根据传递给fit方法的值来决定最合适的算法。 (不同实现方式影响效率)

案例:鸢尾花种类预测

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#1)导入库
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
#2)获取数据
x,y = datasets.load_iris(True)
#3)划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
#4)特征工程:标准化
ss=StandardScaler()
x_train=ss.fit_transform(x_train)
x_test=ss.transform(x_test)
#5)KNN算法预估器(训练数据)
estimator=KNeighborsClassifier(n_neighbors=3) #设置k=3
estimator.fit(x_train,y_train)
#6)模型评估
#方法1:直接比对真实值和预测值
y_predict=estimator.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=estimator.score(x_test,y_test)
print('准确率为:\n',score)

输出结果:

1
2
3
4
5
6
7
8
y_predict:
[0 2 0 2 2 0 2 1 0 1 2 0 2 2 0 0 2 1 0 2 2 1 2 0 1 0 1 0 1 1]
直接比对真实值和预测值:
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True False True]
准确率为:
0.9666666666666667

K-近邻总结

优点:简单,易于理解,易于实现,无需训练
缺点:
1)必须指定K值,K值选择不当则分类精度不能保证
2)懒惰算法,对测试样本分类时的计算量大,内存开销大
使用场景:小数据场景,几千~几万样本,具体场景具体业务去测试

模型选择与调优

什么是交叉验证(cross validation)

交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。

  • 训练集:训练集+验证集

  • 测试集:测试集

    交叉验证过程

通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。

模型选择与调优:

sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)

  • 对估计器的指定参数值进行详尽搜索
  • estimator:估计器对象
  • param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
  • cv:指定几折交叉验证
  • fit:输入训练数据
  • score:准确率
  • 结果分析:
    bestscore:在交叉验证中验证的最好结果_
    bestestimator:最好的参数模型
    cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果

鸢尾花案例调优

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# grid网格,search搜索,cv:cross_validation
# 搜索算法最合适的参数
from sklearn.model_selection import GridSearchCV
#1)获取数据
x,y = datasets.load_iris(True)
#2)划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
#3)特征工程:标准化
ss=StandardScaler()
x_train=ss.fit_transform(x_train)
x_test=ss.transform(x_test)
#4)KNN算法预估器
estimator=KNeighborsClassifier()
#网格搜索GridSearchCV进行最佳参数的查找
params = {'n_neighbors':[i for i in range(1,30)],
'weights':['distance','uniform'],
'p':[1,2]}
# cross_val_score类似
estimator = GridSearchCV(estimator,param_grid=params,scoring='accuracy',cv = 6)
estimator.fit(x_train,y_train)
#5)模型评估
#方法1:直接比对真实值和预测值
y_predict=estimator.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=estimator.score(x_test,y_test)
print('准确率为:\n',score)

#查看了GridSearchCV最佳的参数组合
#最佳参数: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_)

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
y_predict:
[1 1 2 2 1 0 1 0 1 2 1 2 1 0 1 2 1 0 0 2 1 1 1 2 2 2 0 0 1 1]
直接比对真实值和预测值:
[ True True True True True True True True False True True True
True True True True False False True True True True True True
True True True True False True]
准确率为:
0.8666666666666667
最佳参数:
{'n_neighbors': 15, 'p': 2, 'weights': 'distance'}
最佳结果:
0.9833333333333333
最佳估计器:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=None, n_neighbors=15, p=2,
weights='distance')

注:最佳结果—训练集再分为训练集+验证集,验证集的效果;准确率—整体测试集的效果。数据集不同

朴素贝叶斯算法

朴素贝叶斯分类器是基于概率论的分类模型,其思想是先计算样本的先验概率,然后利用贝叶斯公式测算未知样本属于某个类别的后验概率,最终以最大后验概率对应的类别作为未知样本的预测类别。之所以叫”朴素”,是因为整个形式化过程只做最简单、最原始的假设。

理论基础

案例

1234

问题:

1、女神喜欢的概率? $P(喜欢)=\frac{4}{7}$

2、职业是程序员并且体型匀称的概率? $P(程序员,匀称)=\frac{1}{7}$ (联合概率)

3、在女神喜欢的条件下,职业是程序员的概率? $P(程序员|喜欢)=\frac{2}{4}=\frac{1}{2}$ (条件概率)

4、在女神喜欢的条件下,职业是产品,体重是超重的概率?

​ $P(程序员,超重|喜欢)=\frac{1}{4}$ (联合概率、条件概率)

相互独立:$P(AB)=P(A)P(B)$<=>事件A与事件B相互独立

$P(程序员,匀称)=\frac{1}{7}$ $P(程序员)=\frac{3}{7}$ $P(匀称)=\frac{4}{7}$ $P(程序员,匀称)≠P(程序员)P(匀称)$ 不独立

贝叶斯公式:$P(A|B)=\frac{P(B|A)P(A)}{P(B)}$

$P(喜欢|产品经理,超重)=\frac{P(产品经理,超重|喜欢)P(喜欢)}{P(产品经理,超重)}=0$

朴素? 假设:特征与特征之间是相互独立的

朴素贝叶斯算法=朴素+贝叶斯

$P(喜欢|产品经理,超重)=\frac{P(产品经理,超重|喜欢)P(喜欢)}{P(产品经理,超重)}=\frac{P(产品经理|喜欢)P(超重|喜欢)P(喜欢)}{P(产品经理)P(超重)}=\frac{7}{12}$

img

应用场景

朴素贝叶斯算法应用场景:文本分类

公式:$P(C|W)=\frac{P(W|C)P(C)}{P(W)}$

注:$W$为给定文档的特征值(频数统计,预测文档提供),$C$为文档类别

公式如果应用在文章分类的场景当中,我们可以这样看:

其中$C$可以是不同类别

公式分为三个部分:

  • $P(C)$:每个文档类别的概率(某文档类别数/总文档数量)

  • $P(W|C)$:给定类别下特征(被预测文档中出现的词)的概率

    ​ 计算方法:$P(F1│C)=Ni/N $(训练文档中去计算)

    ​ $Ni$为该$F1$词在$C$类别所有文档中出现的次数
    ​ $N$为所属类别$C$下的文档所有词出现的次数和

  • $P(F1,F2,…) $预测文档中每个词的概率

常用贝叶斯分类器

1.高斯贝叶斯分类器

适用条件:自变量X均为连续的数值型
假设条件:自变量X服从高斯正态分布
自变量X的条件概率:$P(xj∣C_i)=\frac{1}{\sqrt{2\pi}\sigma{ji}}exp(-\frac{(xj-\mu{ji})^2}{2\sigma_{ji}^2})$

其中$xj$为第$j$个自变量的取值,$μ{ji}$为训练集中自变量$xj$属于类别 $C_i$的均值,$σ{ji}$为训练集中自变量$x_j$属于类别 $C_i$的标准差。

2.多项式贝叶斯分类器

适用条件:自变量X均为离散型变量
假设条件:自变量X的条件概率服从多项式分布
自变量X的条件概率:$P(xj=x{jk}∣Ci)=\frac{N{ik}+\alpha}{N_i+n\alpha}$

其中$x{jk}$为自变量$x_j$的第$k$个取值,$N{ik}$表示因变量为类别$Ci$时自变量$x_j$取值$x{jk}$的样本个数,$N_i$为类别$C_i$的样本个数,$α$为平滑系数(防止条件概率等于0,通常取1),n为训练文档中统计出的特征词个数。

3.伯努利贝叶斯分类器

适用条件:自变量X均为0-1二元变量
假设条件:自变量X的条件概率服从伯努利分布
自变量X的条件概率

$P(x_j∣C_i)=px_j+(1−p)(1−x_j)$

其中$x_j$为第$j$个自变量,其取值为0或1;$p$表示类别为$C_i$时自变量取1的概率,可以用经验频率代替

$p=P(xj=1∣C_i)=\frac{N{i1}+α}{N_i+nα}$

$N_{i1}$表示在类别$C_i$时自变量$x_j$取1的样本量。

代码实现

1.高斯贝叶斯分类器

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#高斯贝叶斯分类器进行癌症预测
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1、读取数据
column_name = ['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("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data",
names=column_name)
# 2、数据处理—处理缺失值
data = data.replace(to_replace='?', value=np.nan) #1)替换np.nan
data = data.dropna() #2)删除缺失值
print(data.isnull().any()) #确认不存在缺失值
print('-----------------------------------')
# 取出特征值
x = data[column_name[1:10]] #x=data.iloc[:,1:-1]
y = data[column_name[10]] #y=data['Class']
#设置正例和负例
y = y.map({2:0,4:1})
print(y.value_counts())
print('-----------------------------------')
#3、分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
#4、特征工程—标准化
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
#5、estimator估计器流程
from sklearn import naive_bayes
#调用高斯朴素贝叶斯分类器的“类”
gnb = naive_bayes.GaussianNB()
#模型拟合
gnb.fit(x_train,y_train)
#6、进行预测(模型评估)
#模型在测试数据集上的预测
gnb_pred = gnb.predict(x_test)
#各类别的预测数量
print(pd.Series(gnb_pred).value_counts())
print('-----------------------------------')
#导入第三方包
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
#构建混淆矩阵
cm = pd.crosstab(gnb_pred,y_test)
#绘制混淆矩阵图
sns.heatmap(cm,annot = True , cmap = 'GnBu' , fmt = 'd')
#去除x轴和y轴的标签
plt.xlabel('Real')
plt.ylabel('Predict')
#显示图形
plt.show()
print('模型的准确率:\n',metrics.accuracy_score(y_test,gnb_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test,gnb_pred))

#计算正例的预测概率,用于生成ROC曲线的数据
y_score = gnb.predict_proba(x_test)[:,1]
fpr,tpr,threshold = metrics.roc_curve(y_test,y_score)
#计算AUC的值
roc_auc = metrics.auc(fpr,tpr)
#绘制面积图
plt.stackplot(fpr,tpr,color = 'steelblue',alpha = 0.5,edgecolor = 'black')
#添加边际线
plt.plot(fpr,tpr,color= 'black',lw =1)
#添加对角线
plt.plot([0,1],[0,1],color = 'red',linestyle = '--')
#添加文本信息
plt.text(0.5,0.3,'ROC curve(area = %0.2f)'% roc_auc)
#添加x轴与y轴标签
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
#显示图形
plt.show()

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Sample code number             False
Clump Thickness False
Uniformity of Cell Size False
Uniformity of Cell Shape False
Marginal Adhesion False
Single Epithelial Cell Size False
Bare Nuclei False
Bland Chromatin False
Normal Nucleoli False
Mitoses False
Class False
dtype: bool
-----------------------------------
0 444
1 239
Name: Class, dtype: int64
-----------------------------------
0 123
1 82
dtype: int64
-----------------------------------
模型的准确率:
0.9707317073170731
模型的评估报告:
precision recall f1-score support

0 0.99 0.96 0.98 127
1 0.94 0.99 0.96 78

accuracy 0.97 205
macro avg 0.97 0.97 0.97 205
weighted avg 0.97 0.97 0.97 205

12

13

2.多项式贝叶斯分类器

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import pandas as pd
from sklearn import model_selection,naive_bayes,metrics
import matplotlib.pyplot as plt
data=pd.read_csv(r'mushrooms.csv')
print(data.head())
#使用factorize函数将字符型数据做因子化处理,将其转换为整数型数据
#factorize函数返回的是两个元素的元组,第一个元素为转换成的数值,第二个元素为数值对应的字符水平
columns=data.columns[1:]
for column in columns:
data[column]=pd.factorize(data[column])[0]
#拆分为训练集和测试集
x_train,x_test,y_train,y_test=model_selection.train_test_split(data[columns],data.type,test_size=0.25,random_state=1234)
#调用多项式朴素贝叶斯
mnb=naive_bayes.MultinomialNB()
mnb.fit(x_train,y_train)
mnb_pred=mnb.predict(x_test)
#显示预测结果,各类别的预测数量
#模型检验
print('模型的准确率为:',metrics.accuracy_score(y_test,mnb_pred))
print('模型的评估报告:\n',metrics.classification_report(y_test,mnb_pred))
#绘制ROC曲线
y_score=mnb.predict_proba(x_test)[:,1]
fpr,tpr,threshold=metrics.roc_curve(y_test.map({'e':0,'p':1}),y_score)
roc_auc=metrics.auc(fpr,tpr)
plt.stackplot(fpr,tpr,color='steelblue',alpha=0.5,edgecolor='black')
plt.plot(fpr,tpr,color='black',lw=1)
plt.plot([0,1],[0,1],color='red',linestyle='--')
plt.text(0.5,0.3,'ROC Curve (area=%0.2f)' % roc_auc)
plt.xlabel('l-Specificity')
plt.ylabel('Sensitivity')
plt.show()

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  type cap-shape cap-surface  ... spore-print-color population habitat
0 p x s ... k s u
1 e x s ... n n g
2 e b s ... n n m
3 p x y ... k s u
4 e x s ... n a g

[5 rows x 23 columns]
模型的准确率为: 0.8877400295420975
模型的评估报告:
precision recall f1-score support

e 0.85 0.95 0.89 1017
p 0.94 0.83 0.88 1014

accuracy 0.89 2031
macro avg 0.89 0.89 0.89 2031
weighted avg 0.89 0.89 0.89 2031

Figure_1

3.伯努利贝叶斯分类器

未完待续

案例:新闻分类

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#朴素贝叶斯对新闻数据集进行预测
#1)导入库
import numpy as np
from sklearn import datasets
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
#2)获取新闻的数据,20个类别
news = fetch_20newsgroups(subset='all')
#3)进行数据集分割
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.3)
#4)对于文本数据,进行特征抽取
tf = TfidfVectorizer()
x_train = tf.fit_transform(x_train)
#这里打印出来的列表是:训练集当中的所有不同词的组成的一个列表
print(tf.get_feature_names())
# print(x_train.toarray())
x_test = tf.transform(x_test) # 不需要fit_transform
#5)estimator估计器流程
mnb = MultinomialNB(alpha=1.0) #默认alpha=1.0
mnb.fit(x_train, y_train)
#6)进行预测(模型评估)
y_predict = mnb.predict(x_test)
print('预测每篇文章的类别:\n', y_predict[:100])
print('真实类别为:\n', y_test[:100])
print('模型预测的准确率为:\n', mnb.score(x_test, y_test))
#print('模型预测的准确率为:\n',metrics.accuracy_score(y_test,y_predict))
#混淆矩阵
from sklearn.metrics import classification_report
print('模型的评估报告:\n',classification_report(y_test,y_predict))

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
['00', '000', '0000', '00000', '000000', '00000000', '0000000004', '0000000005', '00000000b', '00000001', '00000001b', '00000010',  ···································································   'zzrk', 'zzs', 'zzt', 'zzvsi', 'zzx', 'zzy_3w', 'zzzzzz', 'zzzzzzt', '³ation', 'íålittin', 'ñaustin', 'ýé', 'ÿhooked']
预测每篇文章的类别:
[16 7 2 4 10 3 18 7 8 12 0 13 11 11 0 15 18 10 12 8 12 2 15 7
9 12 15 16 9 0 3 15 8 3 14 17 1 0 15 16 9 2 3 6 5 4 6 14
8 9 13 9 11 12 10 10 3 11 11 0 6 12 15 3 15 6 5 1 9 14 10 3
7 11 0 3 7 16 13 9 5 15 1 13 15 16 7 4 1 16 16 18 14 15 7 16
15 14 0 14]
真实类别为:
[19 7 2 4 10 3 18 3 8 12 0 13 11 11 0 0 18 10 12 15 12 2 15 7
9 12 15 16 9 0 3 15 8 3 14 17 1 0 15 16 9 2 3 8 5 4 6 14
8 9 13 9 11 12 10 10 3 11 11 0 6 12 0 3 0 6 5 1 9 14 12 6
8 12 0 3 7 18 13 9 5 15 1 13 15 16 7 4 1 16 18 18 14 15 7 13
15 1 0 14]
模型预测的准确率为:
0.8593915811814644
模型的评估报告:
precision recall f1-score support

0 0.89 0.76 0.82 235
1 0.93 0.72 0.81 320
···································································
18 0.99 0.63 0.77 235
19 1.00 0.21 0.35 177

accuracy 0.86 5654
macro avg 0.88 0.84 0.84 5654
weighted avg 0.88 0.86 0.85 5654

朴素贝叶斯总结

  • 优点:
    • 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
    • 对缺失数据不太敏感,算法也比较简单,常用于文本分类。
    • 分类准确度高,速度快
  • 缺点:
    • 由于使用了样本属性独立性的假设,所以如果特征属性有关联时其效果不好

决策树

认识决策树

​ 如何高效的进行决策?
​ 特征的先后顺序

决策树分类原理详解

​ 已知 四个特征值 预测 是否贷款给某个人
​ 先看房子,再工作 -> 是否贷款 只看了两个特征
​ 年龄,信贷情况,工作 看了三个特征

信息论基础

1)信息:消除随机不确定性的东西
小明:“我今年18岁” - 信息
小华: ”小明明年19岁” - 不是信息(当小明告诉我他今年18岁,这就消除了对小明年龄的不确定性)
2)信息的衡量标准 -
熵:表示随机变量不确定性的度量 熵单位为比特(bit)

(解释:说白了就是物体内部的混乱程度,比如杂货市场里面什么都有那肯定混乱,专卖店里面只卖一个牌子那就稳定多了)
公式:

熵:不确定性越大,得到的熵值也就越大

3)决策树的划分依据之一———信息增益

特征A对训练数据集D的信息增益$g(D,A)$,定义为集合D的熵$H(D)$与特征A给定条件下D的信息条件熵$H(D|A)$之差,即公式为:

公式的详细解释:

熵的计算:

条件熵的计算公式:

注:$C_{k}$表示属于某个类别的样本数

注:信息增益表示得知特征X的信息而信息的不确定性减少的程度使得类Y的信息熵减少的程度

例子

银行贷款数据

根据某人年龄、工作、房子和信贷情况,判断是否贷款?

在历史数据中(15次贷款)有6次没贷款,9次贷款,所以此时的熵应为:

$H(青年)=-(\frac{2}{5}log_{2}\frac{2}{5}+\frac{3}{5}log_{2}\frac{3}{5})=0.971$

$H(中年)=-(\frac{2}{5}log_{2}\frac{2}{5}+\frac{3}{5}log_{2}\frac{3}{5})=0.971$

$H(老年)=-(\frac{1}{5}log_{2}\frac{1}{5}+\frac{4}{5}log_{2}\frac{4}{5})=0.722$

$H(D|年龄)=\frac{5}{15}H(青年)+\frac{5}{15}H(中年)+\frac{5}{15}H(老年)=0.888$

$g(D,年龄)=H(D)-H(D|年龄)=0.083$ 注:别人计算为0.313

我们以A1、A2、A3、A4代表年龄、有工作、有自己的房子和贷款情况。最终计算的结果g(D, A1) = 0.313, g(D, A2) = 0.324, g(D, A3) = 0.420,g(D, A4) = 0.363。所以我们选择A3 作为划分的第一个特征。这样我们就可以一棵树慢慢建立

决策树的三种算法实现

当然决策树的原理不止信息增益这一种,还有其他方法。但是原理都类似,我们就不去举例计算。

  • ID3

    信息增益 最大的准则

  • C4.5

    信息增益比 最大的准则

  • CART
    分类树: 基尼系数 最小的准则 在sklearn中可以选择划分的默认原则
    优势:划分更加细致(从后面例子的树显示来理解)

决策树算法API

class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)
决策树分类器

  • criterion:默认是’gini’系数,也可以选择信息增益的熵’entropy’

  • max_depth:树的深度大小

  • random_state:随机数种子

  • 其中会有些超参数:max_depth:树的深度大小

其它超参数我们会结合随机森林讲解

案例1:鸢尾花种类预测

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#决策树对鸢尾花进行分类
#1)导入库
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
#2)获取数据
x,y = datasets.load_iris(True)
#3)划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
#决策树不需要特征工程:标准化
#4)决策树算法预估器(训练数据)
estimator=DecisionTreeClassifier(criterion='entropy')
estimator.fit(x_train,y_train)
#5)模型评估
#方法1:直接比对真实值和预测值
y_predict=estimator.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=estimator.score(x_test,y_test)
print('准确率为:\n',score)

输出结果:

1
2
3
4
5
6
7
8
y_predict:
[1 2 0 0 1 2 0 1 2 2 2 1 1 0 1 2 1 0 0 2 2 2 2 2 2 2 0 2 1 2]
直接比对真实值和预测值:
[ True True True True True True True False True True False True
True True True True True True True True False True True True
True True True True True True]
准确率为:
0.9

注:比对kNN算法准确率低;由于鸢尾花数据少,而kNN算法使用场景为小数据场景

决策树可视化

1、sklearn.tree.export_graphviz() 该函数能够导出DOT格式

tree.export_graphviz(estimator,out_file=’tree.dot’,feature_names=[‘’,’’])

2、工具:(能够将dot文件转换为pdf、png)

安装graphviz

ubuntu:sudo apt-get install graphviz Mac:brew install graphviz

3、运行命令

然后我们运行这个命令

dot -Tpng tree.dot -o tree.png

以上文鸢尾花数据为例:

1
2
from sklearn.tree import export_graphviz
export_graphviz(estimator,out_file='iris_tree.dot',feature_names=iris.feature_names)

导出文档iris_tree.dot,打开文档全选复制,粘贴到http://www.webgraphviz.com/网页版上可以实现可视化。无需安装软件。

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

泰坦尼克号数据
在泰坦尼克号和titanic2数据帧描述泰坦尼克号上的个别乘客的生存状态。这里使用的数据集是由各种研究人员开始的。其中包括许多研究人员创建的旅客名单,由Michael A. Findlay编辑。我们提取的数据集中的特征是票的类别,存活,乘坐班,年龄,登陆,home.dest,房间,票,船和性别。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#决策树进行乘客生存预测
#1、导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.feature_extraction import DictVectorizer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier,export_graphviz
from sklearn import tree
#2、获取数据
titan = pd.read_csv("http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt")
#3、数据的处理
x = titan[['pclass', 'age', 'sex']]
y = titan['survived']
# ①缺失值处理,将特征当中有类别的这些特征进行字典特征抽取
x['age'].fillna(x['age'].mean(), inplace=True)
# ②对于x转换成字典数据
x=x.to_dict(orient="records") # [{"pclass": "1st", "age": 29.00, "sex": "female"}, {}]

#4、划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)

#5、字典特征抽取
transfer = DictVectorizer()
x_train = transfer.fit_transform(x_train)
x_test=transfer.transform(x_test) #不需要调用fit_transform
print(transfer.get_feature_names())
print('-----------------------------------------------------')
#print(x)

#决策树不需要特征工程:标准化
#6、决策树算法预估器(训练数据)
estimator=DecisionTreeClassifier(criterion='entropy')
estimator.fit(x_train,y_train)
#7、模型评估
#方法1:直接比对真实值和预测值
y_predict=estimator.predict(x_test)
print('y_predict:\n',y_predict)
print('-----------------------------------------------------')
print('直接比对真实值和预测值:\n',y_test y_predict)
print('-----------------------------------------------------')
#方法2:计算准确率
score=estimator.score(x_test,y_test)
print('准确率为:\n',score)
#8、可视化导出titan_tree.dot文档
export_graphviz(estimator,out_file='titan_tree.dot',feature_names=transfer.get_feature_names())

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
['age', 'pclass=1st', 'pclass=2nd', 'pclass=3rd', 'sex=female', 'sex=male']
-----------------------------------------------------
y_predict:
[0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0
1 0 0 1 1 0 0 1 1 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0
0 1 1 0 0 1 1 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 1 1 1 0 1 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 1 0 0 1 1 0 0 1 0 1 1 0 0 1 0 0 1 0 0 1 0 1 0 1 1 0 1 0 0 0 0 0 0 0
1 1 0 1]
-----------------------------------------------------
直接比对真实值和预测值:
199 True
1308 True
814 True
393 False
560 True
...
955 True
147 True
30 True
923 False
404 True
Name: survived, Length: 263, dtype: bool
-----------------------------------------------------
准确率为:
0.779467680608365

决策树总结

优点:可视化 - 可解释能力强
缺点:容易产生过拟合

改进:

  • 减枝cart算法(决策树API当中已经实现,随机森林参数调优有相关介绍)
  • 随机森林

集成学习方法之随机森林

什么是集成学习方法

集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成组合预测,因此优于任何一个单分类的做出预测。

什么是随机森林

在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。

随机森林原理过程

训练集:特征值 +目标值 N个样本 M个特征

两个随机

训练集随机 - N个样本中随机有放回的抽样N个
bootstrap(随机有放回抽样)
[1, 2, 3, 4, 5]经过随机有放回抽样得到新的树的训练 [2, 2, 3, 1, 5]

特征随机 - 从M个特征中随机抽取m个特征
​ 要求:M >> m 效果:降维

随机森林算法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

  • criterian: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 “log2”, then max_features=log2(n_features).
    ​ If None, then max_features=n_features.

  • bootstrap:boolean,optional(default = True) 是否在构建树时使用放回抽样

  • min_samples_split:节点划分最少样本数
  • min_samples_leaf:叶子节点的最小样本数

超参数:n_estimator, max_depth, min_samples_split,min_samples_leaf

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

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#复制上文中决策树代码比对决策树与随机森林效果
#随机森林进行乘客生存预测
from sklearn.ensemble import RandomForestClassifier
estimator= RandomForestClassifier()
# grid网格,search搜索,cv:cross_validation
# 搜索算法最合适的参数
from sklearn.model_selection import GridSearchCV
#网格搜索GridSearchCV进行最佳参数的查找
params ={"n_estimators": [120,200,300,500,800,1200], "max_depth": [5, 8, 15, 25, 30]}
# cross_val_score类似
estimator = GridSearchCV(estimator,param_grid=params,cv = 6)
estimator.fit(x_train, y_train)
#模型评估
#方法1:直接比对真实值和预测值
y_predict=estimator.predict(x_test)
print('---------------以下为随机森林预测效果-----------------')
print('y_predict:\n',y_predict)
print('随机森林预测的直接比对真实值和预测值:\n',y_test y_predict)
print('-----------------------------------------------------')
#方法2:计算准确率
score=estimator.score(x_test,y_test)
print('随机森林预测的准确率为:\n',score)
print('-----------------------------------------------------')
#查看了GridSearchCV最佳的参数组合
#最佳参数: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_)

输出结果:注:随机森林输出结果等待时间长

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#决策树输出结果:
['age', 'pclass=1st', 'pclass=2nd', 'pclass=3rd', 'sex=female', 'sex=male']
-----------------------------------------------------
y_predict:
[1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0
0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1 0 1 0 0 1 1 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1
0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 1
0 1 0 0 1 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0
0 1 1 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 0 0 0
0 1 1 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1
1 1 0 0]
-----------------------------------------------------
直接比对真实值和预测值:
379 False
1099 True
970 True
482 True
573 True
...
80 True
295 True
4 True
1173 True
684 True
Name: survived, Length: 263, dtype: bool
-----------------------------------------------------
准确率为:
0.7490494296577946

#随机森林输出结果:
---------------以下为随机森林预测效果-----------------
y_predict:
[1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0
0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 1 0 1 0 0 1 1 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1
0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 1 1
0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0
0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1
1 1 0 0]
随机森林预测的直接比对真实值和预测值:
379 False
1099 True
970 True
482 True
573 True
...
80 True
295 True
4 True
1173 True
684 True
Name: survived, Length: 263, dtype: bool
-----------------------------------------------------
随机森林预测的准确率为:
0.7908745247148289
-----------------------------------------------------
最佳参数:
{'max_depth': 5, 'n_estimators': 300}
最佳结果:
0.8295238095238096
最佳估计器:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=5, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=300,
n_jobs=None, oob_score=False, random_state=None,
verbose=0, warm_start=False)

总结

  • 在当前所有算法中,具有极好的准确率
  • 能够有效地运行在大数据集上,处理具有高维特征的输入样本,而且不需要降维
  • 能够评估各个特征在分类问题上的重要性

回归算法

回归问题:目标值 - 连续型的数据

线性回归

什么是线性回归

线性回归(Linear regression)是利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式。

特点:只有一个自变量的情况称为单变量回归(如:$y=kx+b$),大于一个自变量情况的叫做多元回归。

通用公式:$h_w(x)=w_1x_1+w_2x_2+w_3x_3…+b=w^Tx+b$

其中$w$权重,$b$偏置

$w$和$x$可以理解为矩阵:$\mathbf{w}=\left(\begin{array}{c}b \ w{1} \ w{2}\end{array}\right)$,$\mathbf{x}=\left(\begin{array}{c}1 \ x{1} \ x{2}\end{array}\right)$

线性回归当中的关系有两种,一种是线性关系,另一种是非线性关系。

例子:

线性关系

注:如果在单特征与目标值的关系呈直线关系,或者两个特征与目标值呈现平面的关系

数据:工资和年龄(2个特征)

目标:预测银行会贷款给我多少钱(标签)

考虑:工资和年龄都会影响最终银行贷款的结果那么它们各自有多大的影响呢?(参数)

捕获

$X1,X2$就是我们的两个特征(年龄,工资)$ Y$是银行最终会借给我们多少钱

找到最合适的一条线(想象一个高维)来最好的拟合我们的数据点

image-20200302161335608

假设$w_1$是年龄的参数,$w_2$是工资的参数

拟合的平面:$h_w(x)=w_1x_1+w_2x_2$

整合:$h_w(x)=w^Tx$

非线性关系

非线性关系

如果是非线性关系,那么回归方程可以理解为:$w_1x_1+w_2x_2^2+w_3x_3^2$

线性回归原理

1、误差

真实值和预测值之间肯定是要存在差异的(用$ε$来表示该误差)

对于每个样本:$
y^{(i)}=w^{T} x^{(i)}+\varepsilon^{(i)}
$

误差$\varepsilon^{(i)}$是独立同分布,并且服从均值为0方差为$θ^2$的高斯分布(正态分布)

独立:张三和李四一起来贷款,他俩没关系

同分布:他俩都来得是我们假定的这家银行

高斯分布:银行可能会多给,也可能会少给,但是绝大多数情况下这个浮动不会太大,极小情况下浮动会比较大,符合正常情况

预测值与误差:$y^{(i)}=w^{T} x^{(i)}+\varepsilon^{(i)}$ $(1)$

由于误差服从高斯分布:$p(\varepsilon^{(i)})=\frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{(\varepsilon^{(i)})^{2}}{2 \sigma^{2}}\right)$ $(2)$

将$(1)$式代入$(2)$式:$
p(y^{(i)}|x^{(i)};w)=\frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{(y^{(i)}-w^Tx^{(i)})^{2}}{2 \sigma^{2}}\right)
$

似然函数:$L(w)=\prod{i=1}^{m} p\left(y^{(i)} | x^{(i)} ; w\right)=\prod{i=1}^{m} \frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{\left(y^{(i)}-w^{T} x^{(i)}\right)^{2}}{2 \sigma^{2}}\right)$

解释:什么样的参数跟我们的数据组合后恰好是真实值

对数似然:$logL(w)=log\prod_{i=1}^{m} \frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{\left(y^{(i)}-w^{T} x^{(i)}\right)^{2}}{2 \sigma^{2}}\right)$

解释:乘法难解,加法就容易了,对数里面乘法可以转换成加法

展开化简:$\sum{i=1}^{m} \log \frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{\left(y^{(i)}-w^{T} x^{(i)}\right)^{2}}{2 \sigma^{2}}\right)$
$=m \log \frac{1}{\sqrt{2 \pi} \sigma}-\frac{1}{\sigma^{2}} \cdot \frac{1}{2} \sum
{i=1}^{m}\left(y^{(i)}-w^{T} x^{(i)}\right)^{2}$

目标:让似然函数(对数变换后也一样)越大越好

2、损失函数(Loss Function)

$J(w)=\frac{1}{2} \sum{i=1}^{m}\left(y^{(i)}-w^{T} x^{(i)}\right)^{2}=\frac{1}{2} \sum{i=1}^{m}\left(h_w(x^{(i)})-y^{(i)}\right)^{2}$

这里的这个损失函数就是著名的最小二乘损失函数

3、优化算法

如何去求模型当中的W,使得损失最小?(目的是找到最小损失对应的W值)

线性回归经常使用的两种优化算法:

1)正规方程——天才(直接求解$w$)

目标函数:$J(w)=\frac{1}{2} \sum_{i=1}^{m}\left(h_w(x^{(i)})-y^{(i)}\right)^{2}=\frac{1}{2}\left(Xw-y\right)^T\left(Xw-y\right)$

求偏导:

令偏导等于0得:$w=\left(X^TX\right)^{-1}X^Ty$

损失行数求解1

理解:X为特征值矩阵,y为目标值矩阵。直接求到最好的结果

缺点:当特征过多过复杂时,求解速度太慢并且得不到结果

2)梯度下降(Gradient Descent)——勤奋努力的普通人(一步一步的求$w$)

梯度下降公式

理解:α为学习速率,需要手动指定(超参数),α旁边的整体表示方向

沿着这个函数下降的方向找,最后就能找到山谷的最低点,然后更新W值

使用:面对训练数据规模十分庞大的任务 ,能够找到较好的结果

我们通过两个图更好理解梯度下降的过程:

单变量的梯度下降

多变量的梯度下降

4、优化动态图演示

线性回归优化动态图

线性回归算法API

方法一

sklearn.linear_model.LinearRegression(fit_intercept=True)

  • 通过正规方程优化

  • fit_intercept:是否计算偏置

  • LinearRegression.coef:回归系数

  • LinearRegression.intercept:偏置

方法二

sklearn.linear_model.SGDRegressor(loss=”squared_loss”, fit_intercept=True, learning_rate =’invscaling’, eta0=0.01)

  • SGDRegressor类实现了随机梯度下降学习,它支持不同的loss函数和正则化惩罚项来拟合线性回归模型。
  • loss:损失类型 loss=”squared_loss”: 普通最小二乘法
  • fit_intercept:是否计算偏置
  • learning_rate : string, optional

​ 学习率填充

​ ‘constant’: eta = eta0

​ ‘optimal’: eta = 1.0 / (alpha * (t + t0)) [default]

​ ‘invscaling’: eta = eta0 / pow(t, power_t) power_t=0.25:存在父类当中

对于一个常数值的学习率来说,可以使用learning_rate=’constant’ ,并使用eta0来指定学习率。

  • SGDRegressor.coef:回归系数

  • SGDRegressor.intercept:偏置

注:sklearn提供给我们两种实现的API, 可以根据选择使用

波士顿房价预测

代码:(补充完善https://blog.csdn.net/weixin_41890393/article/details/83589860)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#正规方程的优化方法对波士顿房价进行预测
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn import metrics
#1)获取数据
x,y= datasets.load_boston(True)

#平滑处理预测值y
#平滑处理y值,x不处理。(x代表特征,y代表预测值)
#y=np.log(y)

#2)划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,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)模型评估
y_predict=estimator.predict(x_test)
print('预测房价:\n',y_predict)
print('正规方程—均方误差MSE为:', metrics.mean_squared_error(y_test, y_predict))
#7)交叉验证
from sklearn.model_selection import cross_val_predict
predicted = cross_val_predict(estimator,x,y,cv=10)
print("MSE:", metrics.mean_squared_error(y, predicted))
#6)可视化
import matplotlib.pyplot as plt
# scatter
plt.scatter(y, predicted)
# plot
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=4)
plt.xlabel("Measured")
plt.ylabel("Predicted")
plt.show()

#展示结果
#创建画布
plt.figure(figsize=(20,8),dpi=80)
#绘图
plt.rcParams['font.sans-serif']='SimHei'
plt.rcParams['axes.unicode_minus']=False
x=range(len(y_predict))
y1=y_predict
y2=y_test
#折线图
plt.plot(x,y1,linestyle='-')
plt.plot(x,y2,linestyle='-.')
#增加图例
plt.legend(['房价预测值','房价真实值'])
plt.title('波士顿房价走势图')
#展示
plt.show()

输出结果:(注:特征有几个权重就有几个)

1
2
3
4
5
6
7
8
9
10
11
12
正规方程权重系数为:
[-0.64817766 1.14673408 -0.05949444 0.74216553 -1.95515269 2.70902585
-0.07737374 -3.29889391 2.50267196 -1.85679269 -1.75044624 0.87341624
-3.91336869]
正规方程偏置为:
22.62137203166228
预测房价:
[28.22944896 31.5122308 21.11612841 32.6663189 20.0023467 19.07315705
...........................................................
28.58237108]
正规方程—均方误差MSE为: 20.6275137630954
MSE: 34.53965953999329

Figure_1

Figure_19

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#梯度下降的优化方法对波士顿房价进行预测
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import SGDRegressor
from sklearn import metrics
#1)获取数据
x,y= datasets.load_boston(True)

#2)划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=22)
#3)特征工程:标准化
transfer=StandardScaler()
x_train=transfer.fit_transform(x_train)
x_test=transfer.transform(x_test)

#4)梯度下降的优化算法预估器
estimator=SGDRegressor(learning_rate='constant', eta0=0.01,max_iter=10000)#调参数
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)
print('梯度下降—均方误差MSE为:', metrics.mean_squared_error(y_test, y_predict))

输出结果:

1
2
3
4
5
6
7
8
9
10
11
梯度下降权重系数为:
[-0.529811 0.93849958 -0.43482307 0.77305338 -1.71206925 2.82393382
-0.16256326 -3.09703859 1.63812767 -0.93714655 -1.72483573 0.88640923
-3.90806571]
梯度下降截距为:
[22.61725005]
预测房价:
[28.29992805 31.66102185 21.46408381 32.63060514 20.23508805 18.98298548
...........................................................
28.33964857]
梯度下降—均方误差MSE为: 21.004247881383602

正规方程和梯度下降对比

正规方程和梯度下降对比

文字对比

梯度下降正规方程
需要选择学习率不需要
需要迭代求解一次运算得出
特征数量较大可以使用需要计算方程,时间复杂度高O(n3)

选择:

  • 小规模数据:
    • LinearRegression(不能解决拟合问题)
    • 岭回归
  • 大规模数据:SGDRegressor

拓展-关于优化方法BGD、SGD、MBGD、SAG

目标函数:$J(w)=\frac{1}{2m} \sum_{i=1}^{m}\left(y^{(i)}-h_w(x^{(i)})\right)^{2}$

① 批量梯度下降(batch gradient descent):(容易得到最优解,但是由于每次考虑所有样本,速度很慢)

$\frac{\partial J(w)}{\partial w{j}}=-\frac{1}{m} \sum{i=1}^{m}\left(y^{(i)}-h{w}\left(x^{(i)}\right)\right) x{j}^{(i)}$

$w{j}^{\prime}=w{j}+\frac{α}{m} \sum{i=1}^{m}\left(y^{(i)}-h{w}\left(x^{(i)}\right)\right) x_{j}^{(i)}$

批量梯度下降的算法执行过程如下图:

031938497051596

随机梯度下降(Stochastic Gradient Descent, SGD):(每次找一个样本,迭代速度快,但不一定每次都朝着收敛的方向,而是震荡的方式趋向极小点)

$w{j}^{\prime}=w{j}+α\left(y^{(i)}-h{w}\left(x^{(i)}\right)\right) x{j}^{(i)}$

  • SGD的优点是:
    • 高效
    • 容易实现
  • SGD的缺点是:
    • SGD需要许多超参数:比如正则项参数、迭代数。
    • SGD对于特征标准化是敏感的。

③ 小批量梯度下降法(Mini-batch gradient descent):(每次更新选择一小部分数据来算,实用!

$w{j}^{\prime}=w{j}+α\frac{1}{10} \sum{k=i}^{i+9}\left(y^{(k)}-h{w}\left(x^{(k)}\right)\right) x_{j}^{(k)}$

④随机平均梯度法(Stochasitc Average Gradient):(由于收敛的速度太慢,有人提出SAG等基于梯度下降的算法)

Scikit-learn:SGDRegressor、岭回归、逻辑回归等当中都会有SAG优化

欠拟合与过拟合

在这里插入图片描述

  • 欠拟合(模型过于简单)

在这里插入图片描述

  • 过拟合(模型过于复杂)

在这里插入图片描述

解决办法

欠拟合解决办法

  • 增加新的特征,可以考虑加入进特征组合、高次特征,来增大假设空间

  • 采用非线性模型,比如核SVM 、决策树、DNN等模型

  • Boosting,Boosting 往往会有较小的 Bias,比如 Gradient Boosting 等

  • 如果已正则化,尝试减少正则化程度$λ$

过拟合解决办法

  • 交叉检验,通过交叉检验得到较优的模型参数

  • 特征选择,减少特征数或使用较少的特征组合,对于按区间离散化的特征,增大划分的区间

  • 正则化,常用的有 L1、L2 正则

  • 如果已正则化,尝试增大正则化程度λ

  • 增加训练数据可以有限的避免过拟合

  • Bagging,将多个弱学习器Bagging 一下效果会好很多,比如随机森林等

    在这里插入图片描述

    正则化类别

  1. L1正则化
    作用:可以使其中一些W的值直接为0,删除这个特征的影响。
    LOSSO回归
  2. L2正则化
    作用:可以使得其中一些W的值都很小,都接近于0,削弱某个特征的影响。
    优点:越小的参数说明模型越简单,越简单的模型则越不容易产生过拟合现象。
    Ridge回归(岭回归)。
    加入L2正则化后的损失函数:

$J(w)=\frac{1}{2m} \sum{i=1}^{m}\left(y^{(i)}-h_w(x^{(i)})\right)^{2}+λ\sum{j=1}^{n}w_j^2$

其中m为样本数,n为特征数

岭回归

岭回归,其实也是一种线性回归。只不过在算法建立回归方程时候,加上正则化(L2)的限制,从而达到解决过拟合的效果。

参数推导

线性回归模型的目标函数:$J(β)=\sum\left(y-Xβ\right)^{2}$

为了保证回归系数$β$可求,岭回归模型在目标函数上加了一个L2范数的惩罚项

$J(β)=\sum\left(y-Xβ\right)^{2}+λ||β||_2^2=\sum\left(y-Xβ\right)^{2}+\sumλβ^2$

其中$λ$为非负数,$λ$越大,则为了使$J(β)$最小,回归系数$β$就越小。
推导过程:

$\begin{array}{c}
J(\beta)=(y-X \beta)^{T}(y-X \beta)+\lambda \beta^{T} \beta \
=y^{T} y-y^{T} X \beta-\beta^{T} X^{T} y+\beta^{T} X^{T} X \beta+\lambda \beta^{T} \beta \
令 \frac{\partial J(\beta)}{\partial \beta}=0 \
\Rightarrow 0-X^{T} y-X^{T} y+2 X^{T} X \beta+2 \lambda \beta=0 \
\Rightarrow \beta=\left(X^{T} X+\lambda I\right)^{-1} X^{T} y
\end{array}$

L2范数惩罚项的加入使得$(X^{T}X+λI)$满秩,保证了可逆,但是也由于惩罚项的加$λ$,使得回归系数$β$的估计不再是无偏估计。所以岭回归是以放弃无偏性、降低精度为代价解决病态矩阵问题的回归方法。
单位矩阵$I$的对角线上全是1,像一条山岭一样,这也是岭回归名称的由来。

$λ$的选择

模型的方差:回归系数的方差
模型的偏差:预测值和真实值的差异
随着模型复杂度的提升,在训练集上的效果就越好,即模型的偏差就越小;但是同时模型的方差就越大。对于岭回归的$λ$而言,随着$λ$的增大,$(X^{T}X+λI)$就越大,$(X^{T}X+λI)^{-1}$就越小,模型的方差就越小;而$λ$越大使得$β$的估计值更加偏离真实值,模型的偏差就越大。所以岭回归的关键是找到一个合理的$λ$值来平衡模型的方差和偏差。
根据凸优化,可以将岭回归模型的目标函数$J(β)$最小化问题等价于$\left{\begin{array}{l}\operatorname{argmin}\left{\Sigma\left(y-X \beta^{2}\right)\right} \ \Sigma \beta^{2} \leq t\end{array}\right.$

其中$t$为一个常数。以最简单的二维为例,即$β(β_1,β_2)$其几何图形是:

20181103202221367

20181103202237148

抛物面代表的是$\sum(y-X\beta)^2$的部分,圆柱体代表的是$β_1^{1}+β_2^{2}≤t$的部分。最小二乘解是抛物面的中心,岭回归解是抛物面与圆柱体的交点。岭回归的惩罚项$∑λβ^2$是关于回归系数$β$的二次函数,对目标函数求偏导时会保留$β$,抛物面与圆柱体很难相交于轴上使某个变量的回归系数为0,因此岭回归不能实现变量的剔除。

(1)岭迹法确定$λ$值
由$β=(X^TX+λI)^{−1}X^Ty$ 可知$β$是$λ$的函数,当$λ∈[0,∞)$时,在平面直角坐标系中的$β−λ$曲线称为岭迹曲线。当$β$趋于稳定的点就是所要寻找的$λ$值。
代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt
data=pd.read_csv('diabetes.csv')
x=data.iloc[:,1:-1]
y=data['Outcome']
#拆分为训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1234)
#构造不同的lambda值
Lambdas=np.logspace(-5,2,200)
#存放偏回归系数
ridge_cofficients=[]
for Lambda in Lambdas:
ridge=Ridge(alpha=Lambda,normalize=True)
ridge.fit(x_train,y_train)
ridge_cofficients.append(ridge.coef_)

#绘制岭迹曲线
plt.rcParams['font.sans-serif']=['Microsoft YaHei']
plt.rcParams['axes.unicode_minus']=False
plt.style.use('ggplot')
plt.plot(Lambdas,ridge_cofficients)
#x轴做对数处理
plt.xscale('log')
plt.xlabel('Log(Lambda)')
plt.ylabel('Cofficients')
plt.show()

输出结果:

Figure_1

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

书上说在0.01附近大多数回归系数就趋于稳定,这哪看得出?所以定性的方法一般不太靠谱,还是用定量的方法吧!
(2)交叉验证法确定$λ$值

交叉验证法的思想是,将数据集拆分为$k$个数据组(每组样本量大体相当),从$k$组中挑选$k-1$组用于模型的训练,剩下的1组用于模型的测试,则会有$k-1$个训练集和测试集配对,每一种训练集和测试集下都会有对应的一个模型及模型评分(如均方误差),进而可以得到一个平均评分。对于$λ$值则选择平均评分最优的$λ$值。RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, normalize=False, scoring=None, cv=None, gcv_mode=None, store_cv_values=False)•

  • lambdas:用于指定多个$λ$值的元组或数组对象,默认包含0.1,1,10三种值。
  • fit_intercept:bool类型,是否需要拟合截距项,默认为True。

  • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。

  • scoring:指定用于模型评估的度量方法。
  • cv:指定交叉验证的重数。gcv_mode:指定广义交叉验证的方法。
  • store_cv_values:bool类型,是否保存每个λ\lambdaλ下交叉验证的评估信息,默认为False,只有cv为None时有效。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeCV
import matplotlib.pyplot as plt
data=pd.read_csv('diabetes.csv')
x=data.iloc[:,1:-1]
y=data['Outcome']
#拆分为训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1234)
#构造不同的lambda值
Lambdas=np.logspace(-5,2,200)
#设置交叉验证的参数,使用均方误差评估
ridge_cv=RidgeCV(alphas=Lambdas,normalize=True,scoring='neg_mean_squared_error',cv=10)
ridge_cv.fit(x_train,y_train)
print(ridge_cv.alpha_)

输出结果:

1
0.038720387818125535

代码实现

Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver=‘auto’, random_state=None)

  • 具有l2正则化的线性回归

  • alpha:正则化力度,也叫 λ,默认为1。λ取值:0.1~1 ~10

  • fit_intercept:bool类型,是否需要拟合截距项,默认为True。

  • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。

    normalize=False:可以在fit之前调用preprocessing.StandardScaler标准化数据

  • copy_X:bool类型,是否复制自变量X的数值,默认为True。

  • max_iter:指定模型的最大迭代次数。

  • solver:指定模型求解最优化问题的算法,默认为’auto’。

    sag:如果数据集、特征都比较大,选择该随机梯度下降优化

  • random_state:指定随机生成器的种子。

  • Ridge.coef:回归权重

  • Ridge.intercept_:回归偏置

    All last four solvers support both dense and sparse data. However,only ‘sag’ supports sparse input when ‘fit_intercept’is True.

    Ridge方法相当于SGDRegressor(penalty=’l2’, loss=”squared_loss”),只不过SGDRegressor实现了一个普通的随机梯度下降学习,推荐使用Ridge(实现了SAG)

    • sklearn.linearmodel.RidgeCV(_BaseRidgeCV, RegressorMixin)

    • 具有l2正则化的线性回归,可以进行交叉验证

    • coef:回归系数

    1
    2
    3
    4
    5
    class _BaseRidgeCV(LinearModel):
    def __init__(self, alphas=(0.1, 1.0, 10.0),
    fit_intercept=True, normalize=False, scoring=None,
    cv=None, gcv_mode=None,
    store_cv_values=False):

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge,RidgeCV
data=pd.read_csv('diabetes.csv')
x=data.iloc[:,1:-1]
y=data['Outcome']
#拆分为训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1234)
#构造不同的lambda值
Lambdas=np.logspace(-5,2,200)
#设置交叉验证的参数,使用均方误差评估
ridge_cv=RidgeCV(alphas=Lambdas,normalize=True,scoring='neg_mean_squared_error',cv=10)
ridge_cv.fit(x_train,y_train)
print(ridge_cv.alpha_)
#基于最佳lambda值建模
ridge=Ridge(alpha=ridge_cv.alpha_,normalize=True)
ridge.fit(x_train,y_train)
#打印回归系数
print(pd.Series(index=['Intercept']+x_train.columns.tolist(),
data=[ridge.intercept_]+ridge.coef_.tolist()))
#模型评估
ridge_pred=ridge.predict(x_test)
#均方误差
from sklearn.metrics import mean_squared_error
MSE=mean_squared_error(y_test,ridge_pred)
print(MSE)

输出结果:

1
2
3
4
5
6
7
8
9
10
11
0.038720387818125535
Intercept -0.829372
Glucose 0.005658
BloodPressure -0.002019
SkinThickness -0.000805
Insulin -0.000016
BMI 0.012776
DiabetesPedigreeFunction 0.158436
Age 0.004989
dtype: float64
0.16870817670347735

LASSO回归

参数推导

岭回归无法剔除变量,而LASSO回归模型,将惩罚项由L2范数变为L1范数,可以将一些不重要的回归系数缩减为0,达到剔除变量的目的。

$J(β)=\sum\left(y-Xβ\right)^{2}+λ||β||_1=\sum\left(y-Xβ\right)^{2}+\sumλ|β|=ESS(β)+λl_1(β)$

$λ$的选择

直接使用交叉验证法

LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True, normalize=False, precompute=‘auto’, max_iter=1000, tol=0.0001, copy_X=True, cv=None, verbose=False, n_jobs=1, positive=False, random_state=None, selection=‘cyclic’)

  • eps:指代λ\lambdaλ最小值与最大值的商,默认为0.001。
  • n_alphas:指定λ\lambdaλ的个数,默认为100个。
  • alphas:指定具体的λ\lambdaλ列表用于模型的运算。
  • fit_intercept:bool类型,是否需要拟合截距项,默认为True。
  • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
  • precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
  • max_iter:指定模型的最大迭代次数。
  • tol:指定模型收敛的阈值,默认为0.0001。
  • copy_X:bool类型,是否复制自变量X的数值,默认为True。
  • cv:指定交叉验证的重数。
  • verbose:bool类型,是否返回模型运行的详细信息,默认为False。
  • n_jobs:指定使用的CPU数量,默认为1,如果为-1表示所有CPU用于交叉验证的运算。
  • positive:bool类型,是否将回归系数强制为正数,默认为False。
  • random_state:指定随机生成器的种子。
  • selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LassoCV
data=pd.read_csv('diabetes.csv')
x=data.iloc[:,1:-1]
y=data['Outcome']
#拆分为训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1234)
#构造不同的lambda值
Lambdas=np.logspace(-5,2,200)
#设置交叉验证的参数,使用均方误差评估
lasso_cv=LassoCV(alphas=Lambdas,normalize=True,cv=10,max_iter=10000)
lasso_cv.fit(x_train,y_train)
print(lasso_cv.alpha_)

输出结果:

1
0.00011357333583431052

代码实现

Lasso(alpha=1.0, fit_intercept=True, normalize=False, precompute=False, copy_X=True, max_iter=1000, tol=0.0001, warm_start=False, positive=False, random_state=None, selection=‘cyclic’)

  • alphas:指定λ\lambdaλ值,默认为1。
  • fit_intercept:bool类型,是否需要拟合截距项,默认为True。
  • normalize:bool类型,建模时是否对数据集做标准化处理,默认为False。
  • precompute:bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
  • copy_X:bool类型,是否复制自变量X的数值,默认为True。
  • max_iter:指定模型的最大迭代次数。
  • tol:指定模型收敛的阈值,默认为0.0001。
  • warm_start:bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
  • positive:bool类型,是否将回归系数强制为正数,默认为False。
  • random_state:指定随机生成器的种子。
  • selection:指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Lasso,LassoCV
data=pd.read_csv('diabetes.csv')
x=data.iloc[:,1:-1]
y=data['Outcome']
#拆分为训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=1234)
#构造不同的lambda值
Lambdas=np.logspace(-5,2,200)
#设置交叉验证的参数,使用均方误差评估
lasso_cv=LassoCV(alphas=Lambdas,normalize=True,cv=10,max_iter=10000)
lasso_cv.fit(x_train,y_train)
#基于最佳lambda值建模
lasso=Lasso(alpha=lasso_cv.alpha_,normalize=True,max_iter=10000)
lasso.fit(x_train,y_train)
#打印回归系数
print(pd.Series(index=['Intercept']+x_train.columns.tolist(),
data=[lasso.intercept_]+lasso.coef_.tolist()))
#模型评估
lasso_pred=lasso.predict(x_test)
#均方误差
from sklearn.metrics import mean_squared_error
MSE=mean_squared_error(y_test,lasso_pred)
print(MSE)

输出结果:

1
2
3
4
5
6
7
8
9
10
Intercept                  -0.842415
Glucose 0.005801
BloodPressure -0.001983
SkinThickness -0.000667
Insulin -0.000011
BMI 0.012670
DiabetesPedigreeFunction 0.153236
Age 0.004865
dtype: float64
0.16876008361250405

相对于岭回归而言,可以看到LASSO回归剔除了两个变量,降低了模型的复杂度,同时减少了均方误差,提高了模型的拟合效果。

逻辑回归

逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。

逻辑回归的应用场景

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

目的:分类还是回归?经典的二分类算法!

逻辑回归的决策边界:可以是非线性的

逻辑回归的原理

输入

$h_w(x)=w_1x_1+w_2x_2+w_3x_3…+b=w^Tx+b$

Sigmoid函数

公式:$g(z)=\frac{1}{1+e^{-z}}$

自变量取值为任意实数,值域[0,1]

image-20200304105302691

解释:将任意的输入映射到了[0,1]区间,我们在线性回归中可以得到一个预测值,再将该值映射到Sigmoid 函数中这样就完成了由值到概率的转换,也就是分类任务

预测函数:

分类任务:

$P(y=1|x;w)=h_w(x)$ ; $P(y=0|x;w)=1-h_w(x)$

整合得: $P(y|x;w)=(h_w(x))^y(1-h_w(x))^{1-y}$

解释:对于二分类任务(0,1),整合后y取0只保留$(1-h_w(x))^{1-y}$,y取1只保留$(h_w(x))^y$

逻辑回归运算过程

损失以及优化

1、损失

逻辑回归的损失,称之为对数似然损失,公式如下:

  • 分开类别:

单个损失解释

综合完整损失函数:$$
\operatorname{cost}\left(h{\theta}(x), y\right)=\sum{i=1}^{m}-y{i} \log \left(h{\theta}(x)\right)-\left(1-y{i}\right) \log \left(1-h{\theta}(x)\right)

$$

损失计算过程

2、优化

同样使用梯度下降优化算法,去减少损失函数的值。这样去更新逻辑回归前面对应算法的权重参数,提升原本属于1类别的概率,降低原本是0类别的概率。

逻辑回归算法API

sklearn.linear_model.LogisticRegression(solver=’liblinear’, penalty=‘l2’, C = 1.0)

  • solver:优化求解方式

    默认开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数

  • sag:根据数据集自动选择,随机平均梯度下降

  • penalty:正则化的种类

  • C:正则化力度

默认将类别数量少的当做正例

LogisticRegression方法相当于 SGDClassifier(loss=”log”, penalty=” “),SGDClassifier实现了一个普通的随机梯度下降学习,也支持平均随机梯度下降法(ASGD),可以通过设置average=True。而使用LogisticRegression(实现了SAG)良/恶性乳腺癌肿瘤预测

案例:癌症分类预测

良/恶性乳腺癌肿瘤预测

数据描述:

(1)699条样本,共11列数据,第一列用语检索的id,后9列分别是与肿瘤

相关的医学特征,最后一列表示肿瘤类型的数值。

(2)包含16个缺失值,用”?”标出。

原始数据的下载地址:https://archive.ics.uci.edu/ml/machine-learning-databases/

分析:

  • 缺失值处理
  • 标准化处理
  • 逻辑回归预测

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#逻辑回归进行癌症预测
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
# 1、读取数据
column_name = ['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("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data",
names=column_name)
# 2、数据处理—处理缺失值
data = data.replace(to_replace='?', value=np.nan) #1)替换np.nan
data = data.dropna() #2)删除缺失值
print(data.isnull().any()) #确认不存在缺失值
# 取出特征值
x = data[column_name[1:10]] #x=data.iloc[:,1:-1]
y = data[column_name[10]] #y=data['Class']
#3、分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
#4、特征工程—标准化
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 5、使用逻辑回归
lr = LogisticRegression()
lr.fit(x_train, y_train)
#逻辑回归的模型参数:回归系数和偏置
print("权重:\n", lr.coef_)
print("偏置:\n", lr.intercept_)
#6、模型评估
#方法1:直接比对真实值和预测值
y_predict=lr.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=lr.score(x_test,y_test)
print('准确率为:\n',score)

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Sample code number             False
Clump Thickness False
Uniformity of Cell Size False
Uniformity of Cell Shape False
Marginal Adhesion False
Single Epithelial Cell Size False
Bare Nuclei False
Bland Chromatin False
Normal Nucleoli False
Mitoses False
Class False
dtype: bool
权重:
[[1.4449604 0.10902357 0.64529009 1.02979746 0.2544256 1.55064687
0.92516667 0.62683691 0.54739363]]
偏置:
[-1.08426503]
y_predict: #注:2——良性 4——恶性
[4 4 2 4 2 2 4 2 4 4 2 2 4 2 4 2 2 2 2 4 4 2 2 2 4 2 2 4 2 2 2 2 2 2 2 4 2
2 2 4 2 4 2 2 2 4 4 2 2 2 2 4 4 4 2 2 2 4 4 2 4 2 2 4 2 2 2 4 2 4 2 2 4 4
2 2 2 2 2 2 4 4 2 2 2 4 2 4 4 4 4 2 4 2 2 4 2 2 4 2 4 4 2 2 4 2 2 4 2 2 4
2 2 4 2 2 4 2 4 2 2 2 4 4 4 2 4 2 2 2 2 2 4 2 4 2 4 2 4 4 2 4 2 2 2 4 4 2
2 2 2 2 4 2 2 4 4 4 4 2 2 4 4 2 4 4 2 4 2 4 4 4 2 2 4 2 2 2 2 4 2 4 2 4 2
2 4 4 2 4 2 4 2 4 2 2 2 2 4 4 4 4 4 2 4]
直接比对真实值和预测值:
221 True
266 True
4 True
183 True
341 True
...
55 True
132 True
15 True
597 True
479 True
Name: Class, Length: 205, dtype: bool
准确率为:
0.9707317073170731

在很多分类场景当中我们不一定只关注预测的准确率!!!!!

比如以这个癌症举例子!!!我们并不关注预测的准确率,而是关注在所有的样本当中,癌症患者有没有被全部预测(检测)出来。

分类模型的评估

准确率、精确率、召回率、f1_score,混淆矩阵,ks,ks曲线,ROC曲线,psi等。

准确率、精确率、召回率、f1_score

准确率(Accuracy)的定义是:对于给定的测试集,分类模型正确分类的样本数与总样本数之比;

代码示例:

1
2
3
4
5
6
7
8
9
10
11
#1、准确率
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3,9,9,8,5,8]
y_true = [0, 1, 2, 3,2,6,3,5,9]

accuracy_score(y_true, y_pred)
Out[127]: 0.33333333333333331

accuracy_score(y_true, y_pred, normalize=False) # 类似海明距离,每个类别求准确后,再求微平均
Out[128]: 3

精确率(Precision):预测结果为正例样本中真实为正例的比例(了解)

精确率

召回率(Recall):真实为正例的样本中预测结果为正例的比例(查的全,对正样本的区分能力)

召回率:查得全不全 应用:质量检测 次品

召回率

那么怎么更好理解这个两个概念

精确率与召回率理解

F1_score:反映了模型的稳健型

在理想情况下,我们希望模型的精确率越高越好,同时召回率也越高越高,但是,现实情况往往事与愿违,在现实情况下,精确率和召回率像是坐在跷跷板上一样,往往出现一个值升高,另一个值降低,那么,有没有一个指标来综合考虑精确率和召回率了,这个指标就是F值。F值的计算公式为:

$F=\frac{(a^2+1)PR}{a^2*(P+R)}$ 式中:$P:Precision$,$R:Recall$,$a$:权重因子。

当$a=1$时,$F$值便是$F1$值,代表精确率和召回率的权重是一样的,是最常用的一种评价指标。

$F 1=\frac{2 T P}{2 T P+F N+F P}=\frac{2 \cdot \text { Precision } \cdot \text { Recall}}{\text { Precision }+\text { Recall}}$

混淆矩阵

在分类任务下,预测结果(Predicted Condition)与正确标记(True Condition)之间存在四种不同的组合,构成混淆矩阵(适用于多分类)

混淆矩阵一级指标(最底层的):

真实值是positive,模型认为是positive的数量(True Positive=TP);

真实值是positive,模型认为是negative的数量(False Negative=FN):这就是统计学上的第一类错误(Type I Error);

真实值是negative,模型认为是positive的数量(False Positive=FP):这就是统计学上的第二类错误(Type II Error);

真实值是negative,模型认为是negative的数量(True Negative=TN)

img

示例及实现代码

1
2
3
4
5
6
7
8
9
10
11
12
# 假如有一个模型在测试集上得到的预测结果为:
y_true=[1,0,0,2,1,0,3,3,3]# 实际的类别  
y_pred=[1,1,0,2,1,0,1,3,3]# 模型预测的类别  
#使用sklearn模块计算混淆矩阵
from sklearn.metrics import confusion_matrix
confusion_mat=confusion_matrix(y_true,y_pred)
print(confusion_mat) #看看混淆矩阵长啥样 

[[2 1 0 0]
[0 2 0 0]
[0 0 1 0]
[0 1 0 2]]

img

混淆矩阵可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt
import numpy as np
def plot_confusion_matrix(confusion_mat): #将混淆矩阵画图并显示出来''' 
plt.title('Confusion matrix')
plt.imshow(confusion_mat,interpolation='nearest',cmap=plt.cm.gray)
plt.colorbar()
tick_marks=np.arange(confusion_mat.shape[0])
plt.xticks(tick_marks,tick_marks)
plt.yticks(tick_marks,tick_marks)
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()
plot_confusion_matrix(confusion_mat)

Figure_111

分类评估报告API

sklearn.metrics.classification_report(y_true, y_pred, labels=[], target_names=None )

  • y_true:真实目标值
  • y_pred:估计器预测目标值
  • labels:指定类别对应的数字
  • target_names:目标类别名称
  • return:每个类别精确率与召回率

上文逻辑回归进行癌症预测代码+下文代码:

1
2
3
from sklearn.metrics import classification_report
report=classification_report(y_test, lr.predict(x_test), labels=[2, 4], target_names=['良性', '恶性'])
print("精确率和召回率为:",report)

输出结果:

1
2
3
4
5
6
7
8
精确率和召回率为:               precision    recall  f1-score   support

良性 0.98 0.98 0.98 132
恶性 0.96 0.97 0.97 73

accuracy 0.98 205
macro avg 0.97 0.97 0.97 205
weighted avg 0.98 0.98 0.98 205

二级指标

混淆矩阵里面统计的是个数,有时候面对大量的数据,光凭算个数,很难衡量模型的优劣。因此混淆矩阵在基本的统计结果上又延伸了如下4个指标,我称他们是二级指标(通过最底层指标加减乘除得到的):

准确率(Accuracy)—— 针对整个模型

精确率(Precision)

灵敏度(Sensitivity):就是召回率(Recall)

特异度(Specificity)

img

例:

假设这样一个情况,如果99个样本癌症,1个样本非癌症,不管怎样我全都预测正例(默认癌症为正例),准确率就为99%但是这样效果并不好,这就是样本不均衡下的评估问题

解:准确率:99% 召回率:99/99=100% 精确率:99%

F1—score:2*99%/199%=99.497%

AUC:0.5 —不好的模型 AUC下文介绍

  • TPR=100%

  • FPR=1/1=100%

问题:如何衡量样本不均衡下的评估?

ROC曲线和AUC计算

计算ROC值

1
2
3
4
5
6
7
import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
print(roc_auc_score(y_true, y_scores))

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

ROC曲线

  • ROC曲线的横轴就是FPR,纵轴就是TPR,当二者相等时,表示的意义则是:对于不论真实类别是1还是0的样本,分类器预测为1的概率是相等的,此时AUC为0.5

ROC

AUC指标

AUC(AUC值是一个概率值)的概率意义是随机取一对正负样本,正样本得分大于负样本的概率
AUC的最小值为0.5,最大值为1,取值越高越好
AUC=1,完美分类器,采用这个预测模型时,不管设定什么阈值都能得出完美预测。绝大多数预测的场合,不存在完美分类器。
0.5<AUC<1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。

AUC就是ROC 曲线下的面积,通常情况下数值介于0.5-1之间,可以评价分类器的好坏,数值越大说明越好。

AUC计算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:每个样本预测的概率值

代码(接上文代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
print(y_test.head())
#y_true:每个样本的真实类别,必须为0(反例),1(正例)标记
#将y_test 转换成0和1
y_test = np.where(y_test > 2.5, 1, 0) #y_test数值大于2.5设置为1,不大于设置为0
from sklearn.metrics import roc_auc_score
print("AUC指标:", roc_auc_score(y_test, lr.predict(x_test)))

# ROC曲线
# y_score为模型预测正例的概率
y_score = lr.predict_proba(x_test)[:, 1]
# 计算不同阈值下,fpr和tpr的组合之,fpr表示1-Specificity,tpr表示Sensitivity
from sklearn import metrics
fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC
roc_auc = metrics.auc(fpr, tpr)
# 绘制面积图
import matplotlib.pyplot as plt
plt.stackplot(fpr, tpr, color='steelblue', alpha=0.5, edgecolor='black')
# 添加ROC曲线的轮廓
plt.plot(fpr, tpr, color='black', lw=1)
# 添加对角线作为参考线
plt.plot([0, 1], [0, 1], color='red', linestyle='--')
plt.text(0.5, 0.3, 'ROC curve (area=%0.2f)' % roc_auc)
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
plt.show()

输出结果:

1
2
3
4
5
6
7
53     4
503 2
434 2
495 2
595 2
Name: Class, dtype: int64
AUC指标: 0.9556899934597778

Figure_11

总结

  • AUC只能用来评价二分类
  • AUC非常适合评价样本不平衡中的分类器性能

LIft和gain

Lift图衡量的是,与不利用模型相比,模型的预测能力“变好”了多少,lift(提升指数)越大,模型的运行效果越好。
Gain图是描述整体精准度的指标。
计算公式如下:

$Lift=\frac{\frac{TP}{TP+FP}}{\frac{P}{P+N}}$

$Gain=\frac{TP}{TP+FP}$

作图步骤:
(1) 根据学习器的预测结果(注意,是正例的概率值,非0/1变量)对样本进行排序(从大到小)——-这就是截断点依次选取的顺序;
(2) 按顺序选取截断点,并计算Lift和Gain —-也可以只选取n个截断点,分别在1/n,2/n,3/n等位置

20180309191310524

20180309191506788

回归模型的评估

主要有以下方法:

指标描述metrics方法
Mean Absolute Error (MAE)平均绝对误差from sklearn.metrics import mean_absolute_error
Mean Square Error(MSE)平均方差from sklearn.metrics import mean_squared_error
R-SquaredR平方值from sklearn.metrics import r2_score

代码:

1
2
3
4
5
6
7
8
#sklearn的调用
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

mean_absolute_error(y_test,y_predict)
mean_squared_error(y_test,y_predict)
r2_score(y_test,y_predict)

(一)平均绝对误差(Mean Absolute Error,MAE)

平均绝对误差就是指预测值与真实值之间平均相差多大 :

$MAE=\frac{1}{m}\sum_{i=1}^{m}|f_i-y_i|$

平均绝对误差能更好地反映预测值误差的实际情况.

(二)均方误差(Mean Squared Error,MSE)

观测值与真值偏差的平方和与观测次数的比值:

$MSE=\frac{1}{m}\sum_{i=1}^{m}(f_i-y_i)^2$

这也是线性回归中最常用的损失函数,线性回归过程中尽量让该损失函数最小。那么模型之间的对比也可以用它来比较。MSE可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度。

(三)R-square(决定系数)

$R^2=1-\frac{\sum(Y_actual-Y_predict)^2}{\sum(Y_actual-Y_mean)^2}$

1
2
3
4
5
6
#以线性回归为例
lr = LinearRegression()
lr.fit(x_train,y_train)
y_ = lr.predict(X_test)
# R2 决定系数
lr.score(X_test,y_test) #与用from sklearn.metrics import r2_score相同

数学理解: 分母理解为原始数据的离散程度,分子为预测数据和原始数据的误差,二者相除可以消除原始数据离散程度的影响

其实“决定系数”是通过数据的变化来表征一个拟合的好坏。

理论上取值范围$ (-∞,1] $, 正常取值范围为[0 1] ———实际操作中通常会选择拟合较好的曲线计算R²,因此很少出现$-∞$

越接近1,表明方程的变量对y的解释能力越强,这个模型对数据拟合的也较好

越接近0,表明模型拟合的越差

经验值:>0.4, 拟合效果好

缺点:数据集的样本越大,R²越大,因此,不同数据集的模型结果比较会有一定的误差

(四)Adjusted R-Square (校正决定系数)

$R^2_adjusted=1-\frac{(1-R^2)(n-1)}{n-p-1}$

$n$为样本数量,$p$为特征数量

  • 消除了样本数量和特征数量的影响

(五)交叉验证(Cross-Validation)

交叉验证,有的时候也称作循环估计(Rotation Estimation),是一种统计学上将数据样本切割成较小子集的实用方法,该理论是由Seymour Geisser提出的。在给定的建模样本中,拿出大部分样本进行建模型,留小部分样本用刚建立的模型进行预报,并求这小部分样本的预报误差,记录它们的平方加和。这个过程一直进行,直到所有的样本都被预报了一次而且仅被预报一次。把每个样本的预报误差平方加和,称为PRESS(predicted Error Sum of Squares)。
交叉验证的基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set or test set)。首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标。
无论分类还是回归模型,都可以利用交叉验证,进行模型评估,示例代码:

1
2
3
from sklearn.cross_validation import cross_val_score
print(cross_val_score(knn, X_train, y_train, cv=4))
print(cross_cal_score(lr, X, y, cv=2))

模型保存和加载

当训练或者计算好一个模型之后,那么如果别人需要我们提供结果预测,就需要保存模型(主要是保存算法的参数)

sklearn模型的保存和加载API

from sklearn.externals import joblib

  • 保存:joblib.dump(rf, ‘test.pkl’)

  • 加载:estimator = joblib.load(‘test.pkl’)

线性回归的模型保存加载案例

保存

1
2
3
4
5
6
7
#使用线性模型进行预测
#使用正规方程求解
lr = LinearRegression()
#此时在干什么?
lr.fit(x_train, y_train)
#保存训练完结束的模型
joblib.dump(lr, "test.pkl")

加载

1
2
3
4
5
6
7
8
9
10
11
#使用线性模型进行预测
#使用正规方程求解
#lr = LinearRegression()
#此时在干什么?
#lr.fit(x_train, y_train)
#保存训练完结束的模型
#joblib.dump(lr, "test.pkl")
#当上步模型已经保存好了就不需要训练fit和保存模型了
#通过已有的模型去预测房价
model = joblib.load("test.pkl")
print("从文件加载进来的模型预测房价的结果:", std_y.inverse_transform(model.predict(x_test)))

无监督学习-K-means算法

什么是无监督学习

没有目标值—无监督学习

例:

  • 一家广告平台需要根据相似的人口学特征和购买习惯将美国人口分成不同的小组,以便广告客户可以通过有关联的广告接触到他们的目标客户。

  • Airbnb 需要将自己的房屋清单分组成不同的社区,以便用户能更轻松地查阅这些清单。

  • 一个数据科学团队需要降低一个大型数据集的维度的数量,以便简化建模和降低文件大小。

我们可以怎样最有用地对其进行归纳和分组?我们可以怎样以一种压缩格式有效地表征数据?这都是无监督学习的目标,之所以称之为无监督,是因为这是从无标签的数据开始学习的。

无监督学习包含算法

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

K-means原理

我们先来看一下一个K-means的聚类效果图

K-means如何聚类效果

K-means聚类步骤

1、随机设置K个特征空间内的点作为初始的聚类中心

2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别

3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)

4、如果计算得出的新中心点与原中心点一样,那么结束,否则重新进行第二步过程

K—超参数 根据以下确定: 1)看需求;2)调节超参数

我们以一张图来解释效果
K-means过程分析

K-means算法API

sklearn.cluster.KMeans(n_clusters=8,init=‘k-means++’)

  • k-means聚类

  • n_clusters:开始的聚类中心数量

  • init:初始化方法,默认为’k-means ++’

  • labels_:默认标记的类型,可以和真实值比较(不是值比较)

案例:k-means对Instacart Market用户聚类

分析

  • 1、PCA降维数据
  • 2、k-means聚类
  • 3、聚类结果显示

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import pandas as pd
# 1、获取数据
order_products = pd.read_csv("./instacart/order_products__prior.csv")
products = pd.read_csv("./instacart/products.csv")
orders = pd.read_csv("./instacart/orders.csv")
aisles = pd.read_csv("./instacart/aisles.csv")
# 2、合并表
# order_products__prior.csv:订单与商品信息
# 字段:order_id, product_id, add_to_cart_order, reordered
# products.csv:商品信息
# 字段:product_id, product_name, aisle_id, department_id
# orders.csv:用户的订单信息
# 字段:order_id,user_id,eval_set,order_number,….
# aisles.csv:商品所属具体物品类别
# 字段: aisle_id, aisle
# 合并aisles和products aisle和product_id
tab1 = pd.merge(aisles, products, on=["aisle_id", "aisle_id"])
tab2 = pd.merge(tab1, order_products, on=["product_id", "product_id"])
tab3 = pd.merge(tab2, orders, on=["order_id", "order_id"])
#print(tab3.head())
# 3、找到user_id和aisle之间的关系
table = pd.crosstab(tab3["user_id"], tab3["aisle"])
data = table[:10000] #缩小数据
# 4、PCA降维
from sklearn.decomposition import PCA
# 1)实例化一个转换器类
transfer = PCA(n_components=0.95)
# 2)调用fit_transform
data_new = transfer.fit_transform(data)
print(data_new.shape)
#5、预估器流程
from sklearn.cluster import KMeans
estimator=KMeans(n_clusters=3)
#KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
# n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
# random_state=None, tol=0.0001, verbose=0)
estimator.fit(data_new)
y_predict=estimator.predict(data_new)
print(y_predict[:300])

输出结果:

1
2
3
4
5
6
7
8
9
10
(10000, 42)
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 0
1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1
0 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1
1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 2 1 0 1 1 1 0 1 1
1 1 1 0 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 0 1 1 1 1 1 2 1 1 1 2 1 1 1 1 0 1 0 1
2 1 1 1 0 1 1 1 1 2 0 0 1 0 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
1 1 0 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 1 1 0 1 1 1 1 2 0 1 1 1 1 0 1
1 1 1 0]

问题:如何去评估聚类的效果呢?

Kmeans性能评估指标

轮廓系数

$SC_i=\frac{b_i-a_i}{max(b_i,a_i)}$

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

轮廓系数值分析

img

分析过程(我们以一个蓝1点为例)

1、计算出蓝1离本身族群所有点的距离的平均值a_i

2、蓝1到其它两个族群的距离计算出平均值红平均,绿平均,取最小的那个距离作为b_i

根据公式:极端值考虑:如果b_i >>a_i: 那么公式结果趋近于1;如果a_i>>>b_i: 那么公式结果趋近于-1

结论

如果$b_i>>a_i$:趋近于1效果越好,$ b_i<<a_i$:趋近于-1,效果不好。轮廓系数的值是介于 [-1,1] ,越趋近于1代表内聚度和分离度都相对较优。

轮廓系数API

sklearn.metrics.silhouette_score(X, labels)

  • 计算所有样本的平均轮廓系数
  • X:特征值
  • labels:被聚类标记的目标值

用户聚类结果评估

代码接上文代码:

1
2
3
#6、模型评估—轮廓系数
from sklearn.metrics import silhouette_score
print(silhouette_score(data_new,y_predict))

输出结果:

1
0.5396819903993842

K-means总结

  • 特点分析:采用迭代式算法,直观易懂并且非常实用
  • 缺点:容易收敛到局部最优解(多次聚类)

注:聚类一般做在分类之前

SVM算法

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#SVC算法进行癌症预测
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1、读取数据
column_name = ['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("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data",
names=column_name)
# 2、数据处理—处理缺失值
data = data.replace(to_replace='?', value=np.nan) #1)替换np.nan
data = data.dropna() #2)删除缺失值
print(data.isnull().any()) #确认不存在缺失值
# 取出特征值
x = data[column_name[1:10]] #x=data.iloc[:,1:-1]
y = data[column_name[10]] #y=data['Class']
#3、分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
#4、特征工程—标准化
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 5、使用SVC算法
from sklearn import svm #支持向量机#
module = svm.SVC()
module.fit(x_train, y_train)
#6、模型评估
#方法1:直接比对真实值和预测值
y_predict=module.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=module.score(x_test,y_test)
print('准确率为:\n',score)
from sklearn.metrics import classification_report
report=classification_report(y_test, module.predict(x_test), labels=[2, 4], target_names=['良性', '恶性'])
print("精确率和召回率为:",report)
print(y_test.head())
#y_true:每个样本的真实类别,必须为0(反例),1(正例)标记
#将y_test 转换成0和1
y_test = np.where(y_test > 2.5, 1, 0) #y_test数值大于2.5设置为1,不大于设置为0
from sklearn.metrics import roc_auc_score
print("AUC指标:", roc_auc_score(y_test, module.predict(x_test)))

# ROC曲线
# y_score为模型预测正例的概率
###通过decision_function()计算得到的y_score的值,用在roc_curve()函数中
y_score = module.fit(x_train, y_train).decision_function(x_test)
# 计算不同阈值下,fpr和tpr的组合之,fpr表示1-Specificity,tpr表示Sensitivity
from sklearn import metrics
fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC
roc_auc = metrics.auc(fpr, tpr)
# 绘制面积图
import matplotlib.pyplot as plt
plt.stackplot(fpr, tpr, color='steelblue', alpha=0.5, edgecolor='black')
# 添加ROC曲线的轮廓
plt.plot(fpr, tpr, color='black', lw=1)
# 添加对角线作为参考线
plt.plot([0, 1], [0, 1], color='red', linestyle='--')
plt.text(0.5, 0.3, 'ROC curve (area=%0.2f)' % roc_auc)
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
plt.show()

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Sample code number             False
Clump Thickness False
Uniformity of Cell Size False
Uniformity of Cell Shape False
Marginal Adhesion False
Single Epithelial Cell Size False
Bare Nuclei False
Bland Chromatin False
Normal Nucleoli False
Mitoses False
Class False
dtype: bool
y_predict:
[2 4 2 2 2 2 2 2 2 4 2 2 4 4 2 2 2 2 2 2 4 4 2 2 2 4 4 4 2 4 4 4 2 2 2 2 2
4 2 2 2 2 4 2 2 2 4 2 4 2 2 2 2 4 4 4 2 4 2 2 2 2 4 2 4 2 2 4 2 2 2 2 4 2
2 2 2 2 2 2 2 4 2 2 2 2 2 4 2 2 2 2 4 2 4 2 2 4 2 2 2 4 4 2 2 2 2 4 4 2 4
2 4 2 4 4 2 2 2 4 4 4 2 4 2 2 2 2 2 2 4 2 2 2 2 2 2 4 2 4 4 2 4 2 2 2 4 2
4 4 2 4 4 2 2 2 2 2 2 2 4 4 2 2 2 2 4 2 4 2 2 4 2 2 4 4 2 2 4 2 2 4 4 2 4
4 2 4 4 2 2 2 4 2 2 2 2 4 2 4 2 4 4 4 2]
直接比对真实值和预测值:
492 True
236 True
208 True
518 True
81 True
...
653 True
434 False
196 False
210 True
137 True
Name: Class, Length: 205, dtype: bool
准确率为:
0.9658536585365853
精确率和召回率为: precision recall f1-score support

良性 0.99 0.96 0.97 139
恶性 0.92 0.98 0.95 66

accuracy 0.97 205
macro avg 0.95 0.97 0.96 205
weighted avg 0.97 0.97 0.97 205

492 2
236 4
208 2
518 2
81 2
Name: Class, dtype: int64
AUC指标: 0.9708415086112929

Figure_15

GBDT算法

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#GBDT进行癌症预测
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 1、读取数据
column_name = ['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("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data",
names=column_name)
# 2、数据处理—处理缺失值
data = data.replace(to_replace='?', value=np.nan) #1)替换np.nan
data = data.dropna() #2)删除缺失值
print(data.isnull().any()) #确认不存在缺失值
# 取出特征值
x = data[column_name[1:10]] #x=data.iloc[:,1:-1]
y = data[column_name[10]] #y=data['Class']
#3、分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
#4、特征工程—标准化
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
# 5、使用GBDT
from sklearn.ensemble import GradientBoostingClassifier #Gradient Boosting 和 AdaBoost算法#
from sklearn.ensemble import GradientBoostingRegressor
module = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=1, random_state=0)
module.fit(x_train, y_train)
#6、模型评估
#方法1:直接比对真实值和预测值
y_predict=module.predict(x_test)
print('y_predict:\n',y_predict)
print('直接比对真实值和预测值:\n',y_test y_predict)
#方法2:计算准确率
score=module.score(x_test,y_test)
print('准确率为:\n',score)
from sklearn.metrics import classification_report
report=classification_report(y_test, module.predict(x_test), labels=[2, 4], target_names=['良性', '恶性'])
print("精确率和召回率为:",report)
print(y_test.head())
#y_true:每个样本的真实类别,必须为0(反例),1(正例)标记
#将y_test 转换成0和1
y_test = np.where(y_test > 2.5, 1, 0) #y_test数值大于2.5设置为1,不大于设置为0
from sklearn.metrics import roc_auc_score
print("AUC指标:", roc_auc_score(y_test, module.predict(x_test)))

# ROC曲线
# y_score为模型预测正例的概率
y_score = module.predict_proba(x_test)[:, 1]
# 计算不同阈值下,fpr和tpr的组合之,fpr表示1-Specificity,tpr表示Sensitivity
from sklearn import metrics
fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC
roc_auc = metrics.auc(fpr, tpr)
# 绘制面积图
import matplotlib.pyplot as plt
plt.stackplot(fpr, tpr, color='steelblue', alpha=0.5, edgecolor='black')
# 添加ROC曲线的轮廓
plt.plot(fpr, tpr, color='black', lw=1)
# 添加对角线作为参考线
plt.plot([0, 1], [0, 1], color='red', linestyle='--')
plt.text(0.5, 0.3, 'ROC curve (area=%0.2f)' % roc_auc)
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
plt.show()

本文标题:机器学习课程

文章作者:TJYS

发布时间:2020年03月28日 - 00:00:00

最后更新:2021年10月05日 - 01:39:53

原始链接:https://qikaile.tk/Machine-learning-note.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------
0%