机器学习概述
什么是机器学习
机器学习是从**数据中自动分析获得规律(模型),并利用规律对未知数据进行预测**。
机器学习算法分类
监督学习
目标值:类别—分类问题
KNN、贝叶斯分类、决策树与随机森林、逻辑回归
目标值:连续型数据—回归问题
线性回归、岭回归
无监督学习
目标值:无
聚类K-means

机器学习开发流程
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}]
transfer = DictVectorizer(sparse=False)
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)
print(tf.get_feature_names())
x_test = tf.transform(x_test)
|
代码:
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): 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)
transfer = CountVectorizer()
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
Binarizer(threshold=3).fit_transform(X)
|
(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('----------------------------------------------------------------------')
feature = df.iloc[:, :-1] print(feature) print('----------------------------------------------------------------------')
feature=feature.to_dict(orient="records")
from sklearn.feature_extraction import DictVectorizer dvec = DictVectorizer(sparse=False) X = dvec.fit_transform(feature) print(dvec.get_feature_names()) print('----------------------------------------------------------------------') print(X) print('----------------------------------------------------------------------')
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']
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$
公式表达为:
$$
\begin{equation} z = \frac{x - \mu}{\sigma}\end{equation}
$$
使用preproccessing库的StandardScaler类对数据进行标准化的代码如下:
1 2 3 4
| from sklearn.preprocessing import StandardScaler
ss=StandardScaler() X1=ss.fit_transform(X)
|
归一化:处理后的所有特征的值都会被压缩到 0到1区间上.这样做还可以抑制离群值对结果的影响.
公式表达为:
$$
{\begin{equation} X_{norm} = \frac{X - X_{min}}{X_{max}-X_{min}} \end{equation}}
$$
使用preproccessing库的MinMaxScaler类对数据进行区间缩放的代码如下:
1 2 3 4
| from sklearn.preprocessing import MinMaxScaler
mms=MinMaxScaler() X2=mms.fit_transform(X)
|
正则化
正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。
该方法主要应用于文本分类和聚类中。
1 2 3
| from sklearn.preprocessing import Normalizer ss=Normalizer() X3=ss.fit_transform(X)
|
标准化与正则化的区别
简单来说,**标准化是依照特征矩阵的列处理数据,其通过求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的样本频数的观察值与期望的差距,构建统计量:
$$
\chi^{2}=\sum \frac{(A-E)^{2}}{E}
$$
假设有两个分类变量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)
|
输出结果:
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)
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
| 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()
|

注:特征与特征之间相关性很高: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]
|
输出结果:
更多类似的例子参考 sample plots 。另外,如果仅仅根据相关系数这个值来判断的话,有时候会具有很强的误导性,如 Anscombe’s quartet ,最好把数据可视化出来,以免得出错误的结论。
互信息和最大信息系数 (Mutual information and maximal information coefficient (MIC)
经典的互信息(互信息为随机变量X与Y之间的互信息$I(X;Y)$为单个事件之间互信息的数学期望)也是评价定性自变量对定性因变量的相关性的,互信息计算公式如下:
$$
I(X ; Y)=\sum_{x \in X} \sum_{y \in Y} p(x, y) \log \frac{p(x, y)}{p(x) p(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())
|
输出结果:
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
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)) 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)
基本思想:构造原变量的一系列线性组合形成几个综合指标,以**去除数据的相关性**,并使低维数据最大程度保持原始高维数据的方差信息。
主成分个数的确定:
- 贡献率:第i个主成分的方差在全部方差中所占比重,反映第i个主成分所提取的总信息的份额。
- 累计贡献率:前k个主成分在全部方差中所占比重
- 主成分个数的确定:累计贡献率>0.85
相关系数矩阵or协方差阵?
当涉及变量的量纲不同或取值范围相差较大的指标时,应考虑从相关系数矩阵出发进行主成分分析;(相关系数矩阵消除了量纲的影响。)对同度量或取值范围相差不大的数据,从协方差阵出发。
使用decomposition库的PCA类选择特征的代码如下:
1 2 3 4
| from sklearn.decomposition import PCA
PCA(n_components=2).fit_transform(X)
|
n_components:
- 小数:表示保留百分之多少的信息
- 整数:减少到多少特征
线性判别分析法(LDA)
至多能把C类数据降维到C-1维子空间
使用lda库的LDA类选择特征的代码如下:
1 2 3 4
| from sklearn.lda import LDA
LDA(n_components=2).fit_transform(X,Y)
|
小结

分类算法
分类问题:目标值—类别
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个“邻居”的信息来进行预测。
如何确定谁是邻居?
计算距离:
距离公式:
欧氏距离:$$d = \sqrt{(x1 - y1)^2 + (x2 - y2)^2 + (x3 - y3)^2 + ……}$$
曼哈顿距离—绝对值距离
明可夫斯基距离:欧氏距离和曼哈顿距离的推广 metric_params=None

图中**红线代表曼哈顿距离,绿线代表欧氏距离,也就是直线距离,而蓝线和黄线**代表等价的曼哈顿距离。
电影类型分析
假设我们有现在几部电影

其中? 号电影不知道类别,如何去预测?我们可以利用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
| 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
x,y = datasets.load_iris(True)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
ss=StandardScaler() x_train=ss.fit_transform(x_train) x_test=ss.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)
|
输出结果:
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折交叉验证。
训练集:训练集+验证集
测试集:测试集

超参数搜索-网格搜索(Grid Search)
通常情况下,有很多参数是需要手动指定的(如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
from sklearn.model_selection import GridSearchCV
x,y = datasets.load_iris(True)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
ss=StandardScaler() x_train=ss.fit_transform(x_train) x_test=ss.transform(x_test)
estimator=KNeighborsClassifier()
params = {'n_neighbors':[i for i in range(1,30)], 'weights':['distance','uniform'], 'p':[1,2]}
estimator = GridSearchCV(estimator,param_grid=params,scoring='accuracy',cv = 6) 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)
print('最佳参数:\n',estimator.best_params_)
print('最佳结果:\n',estimator.best_score_)
print('最佳估计器:\n',estimator.best_estimator_)
|
输出结果:
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')
|
注:最佳结果—训练集再分为训练集+验证集,验证集的效果;准确率—整体测试集的效果。数据集不同
朴素贝叶斯算法
朴素贝叶斯分类器是基于概率论的分类模型,其思想是先计算样本的先验概率,然后利用贝叶斯公式测算未知样本属于某个类别的后验概率,最终以最大后验概率对应的类别作为未知样本的预测类别。之所以叫”朴素”,是因为整个形式化过程只做最简单、最原始的假设。
理论基础
案例

问题:
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}$

应用场景
朴素贝叶斯算法应用场景:文本分类
公式:$P(C|W)=\frac{P(W|C)P(C)}{P(W)}$
注:$W$为给定文档的特征值(频数统计,预测文档提供),$C$为文档类别
公式如果应用在文章分类的场景当中,我们可以这样看:
$$
P(C|F1,F2,…)=\frac{P(F1,F2,…|C)P(C)}{P(F1,F2,…)}
$$
其中$C$可以是不同类别
公式分为三个部分:
$P(C)$:每个文档类别的概率(某文档类别数/总文档数量)
$P(W|C)$:给定类别下特征(被预测文档中出现的词)的概率
计算方法:$P(F1│C)=Ni/N $(训练文档中去计算)
$Ni$为该$F1$词在$C$类别所有文档中出现的次数
$N$为所属类别$C$下的文档所有词出现的次数和
$P(F1,F2,…) $预测文档中每个词的概率
常用贝叶斯分类器
1.高斯贝叶斯分类器
适用条件:自变量X均为连续的数值型
假设条件:自变量X服从高斯正态分布
自变量X的条件概率:$P(x_j∣C_i)=\frac{1}{\sqrt{2\pi}\sigma_{ji}}exp(-\frac{(x_j-\mu_{ji})^2}{2\sigma_{ji}^2})$
其中$x_j$为第$j$个自变量的取值,$μ_{ji}$为训练集中自变量$x_j$属于类别 $C_i$的均值,$σ_{ji}$为训练集中自变量$x_j$属于类别 $C_i$的标准差。
2.多项式贝叶斯分类器
适用条件:自变量X均为离散型变量
假设条件:自变量X的条件概率服从多项式分布
自变量X的条件概率:$P(x_j=x_{jk}∣C_i)=\frac{N_{ik}+\alpha}{N_i+n\alpha}$
其中$x_{jk}$为自变量$x_j$的第$k$个取值,$N_{ik}$表示因变量为类别$C_i$时自变量$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(x_j=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
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)
data = data.replace(to_replace='?', value=np.nan) data = data.dropna() print(data.isnull().any()) print('-----------------------------------')
x = data[column_name[1:10]] y = data[column_name[10]]
y = y.map({2:0,4:1}) print(y.value_counts()) print('-----------------------------------')
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test)
from sklearn import naive_bayes
gnb = naive_bayes.GaussianNB()
gnb.fit(x_train,y_train)
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')
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))
y_score = gnb.predict_proba(x_test)[:,1] fpr,tpr,threshold = metrics.roc_curve(y_test,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('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
|


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())
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))
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
|

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
|
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
news = fetch_20newsgroups(subset='all')
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size=0.3)
tf = TfidfVectorizer() x_train = tf.fit_transform(x_train)
print(tf.get_feature_names())
x_test = tf.transform(x_test)
mnb = MultinomialNB(alpha=1.0) mnb.fit(x_train, y_train)
y_predict = mnb.predict(x_test) print('预测每篇文章的类别:\n', y_predict[:100]) print('真实类别为:\n', y_test[:100]) print('模型预测的准确率为:\n', mnb.score(x_test, y_test))
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)
(解释:说白了就是物体内部的混乱程度,比如杂货市场里面什么都有那肯定混乱,专卖店里面只卖一个牌子那就稳定多了)
公式:
$$
H(D)=-\sum_{i=1}^{n} p(x i) * \log _{2} p(x i)
$$
熵:不确定性越大,得到的熵值也就越大
3)决策树的划分依据之一——信息增益
特征A对训练数据集D的信息增益$g(D,A)$,定义为集合D的熵$H(D)$与特征A给定条件下D的信息条件熵$H(D|A)$之差,即公式为:$$g(D,A)=H(D)-H(D|A)$$
公式的详细解释:
熵的计算:$$H(D)=-\sum_{k=1}^{K} \frac{\left|C_{k}\right|}{|D|} \log_{2} \frac{\left|C_{k}\right|}{|D|}$$
条件熵的计算公式:$$
H(D | A)=\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} H\left(D_{i}\right)=-\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} \sum_{k=1}^{K} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|} \log_{2} \frac{\left|D_{i k}\right|}{\left|D_{i}\right|}$$
注:$C_{k}$表示属于某个类别的样本数
注:信息增益表示得知特征X的信息而信息的不确定性减少的程度使得类Y的信息熵减少的程度
例子

根据某人年龄、工作、房子和信贷情况,判断是否贷款?
在历史数据中(15次贷款)有6次没贷款,9次贷款,所以此时的熵应为:
$$H(D)=-(\frac{6}{15}*log_{2}\frac{6}{15}+\frac{9}{15}*log_{2}\frac{9}{15})=0.971$$
$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 作为划分的第一个特征。这样我们就可以一棵树慢慢建立
决策树的三种算法实现
当然决策树的原理不止信息增益这一种,还有其他方法。但是原理都类似,我们就不去举例计算。
决策树算法API
class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)
决策树分类器
其它超参数我们会结合随机森林讲解
案例1:鸢尾花种类预测
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
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
x,y = datasets.load_iris(True)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
estimator=DecisionTreeClassifier(criterion='entropy') 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)
|
输出结果:
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
|
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
titan = pd.read_csv("http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt")
x = titan[['pclass', 'age', 'sex']] y = titan['survived']
x['age'].fillna(x['age'].mean(), inplace=True)
x=x.to_dict(orient="records")
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2)
transfer = DictVectorizer() x_train = transfer.fit_transform(x_train) x_test=transfer.transform(x_test) print(transfer.get_feature_names()) print('-----------------------------------------------------')
estimator=DecisionTreeClassifier(criterion='entropy') estimator.fit(x_train,y_train)
y_predict=estimator.predict(x_test) print('y_predict:\n',y_predict) print('-----------------------------------------------------') print('直接比对真实值和预测值:\n',y_test y_predict) print('-----------------------------------------------------')
score=estimator.score(x_test,y_test) print('准确率为:\n',score)
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()
from sklearn.model_selection import GridSearchCV
params ={"n_estimators": [120,200,300,500,800,1200], "max_depth": [5, 8, 15, 25, 30]}
estimator = GridSearchCV(estimator,param_grid=params,cv = 6) estimator.fit(x_train, y_train)
y_predict=estimator.predict(x_test) print('---------------以下为随机森林预测效果-----------------') print('y_predict:\n',y_predict) print('随机森林预测的直接比对真实值和预测值:\n',y_test y_predict) print('-----------------------------------------------------')
score=estimator.score(x_test,y_test) print('随机森林预测的准确率为:\n',score) print('-----------------------------------------------------')
print('最佳参数:\n',estimator.best_params_)
print('最佳结果:\n',estimator.best_score_)
print('最佳估计器:\n',estimator.best_estimator_)
|
输出结果:注:随机森林输出结果等待时间长
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$是银行最终会借给我们多少钱
找到最合适的一条线(想象一个高维)来最好的拟合我们的数据点

假设$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)$
求偏导:
$$
\begin{aligned}
&\nabla_{w} J(w)=\nabla_{w}\left(\frac{1}{2}(X w-y)^{r}(X w-y)\right)=\nabla_{w}\left(\frac{1}{2}\left(w^{T} X^{T}-y^{T}\right)(X w-y)\right)\
&=\nabla_{w}\left(\frac{1}{2}\left(w^{T} X^{T} X w-w^{T} X^{T} y-y^{T} X w+y^{T} y\right)\right)\
&=\frac{1}{2}\left(2 X^{T} X w-X^{T} y-\left(y^{T} X\right)^{\bar{T}}\right)=X^{T} X w-X^{T} y
\end{aligned}
$$
令偏导等于0得:$w=\left(X^TX\right)^{-1}X^Ty$

理解:X为特征值矩阵,y为目标值矩阵。直接求到最好的结果
缺点:当特征过多过复杂时,求解速度太慢并且得不到结果
2)**梯度下降(Gradient Descent)**——勤奋努力的普通人(一步一步的求$w$)

理解:α为学习速率,需要手动指定(超参数),α旁边的整体表示方向
沿着这个函数下降的方向找,最后就能找到山谷的最低点,然后更新W值
使用:面对训练数据规模十分庞大的任务 ,能够找到较好的结果
我们通过两个图更好理解梯度下降的过程:


4、优化动态图演示

线性回归算法API
方法一
sklearn.linear_model.LinearRegression(fit_intercept=True)
方法二
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来指定学习率。
注: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
x,y= datasets.load_boston(True)
x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=22)
estimator=LinearRegression() estimator.fit(x_train,y_train)
print('正规方程权重系数为:\n',estimator.coef_) print('正规方程偏置为:\n',estimator.intercept_)
y_predict=estimator.predict(x_test) print('预测房价:\n',y_predict) print('正规方程—均方误差MSE为:', metrics.mean_squared_error(y_test, y_predict))
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))
import matplotlib.pyplot as plt
plt.scatter(y, predicted)
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
|


代码:
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
x,y= datasets.load_boston(True)
x_train,x_test,y_train,y_test = train_test_split(x,y,random_state=22)
transfer=StandardScaler() x_train=transfer.fit_transform(x_train) x_test=transfer.transform(x_test)
estimator=SGDRegressor(learning_rate='constant', eta0=0.01,max_iter=10000) estimator.fit(x_train,y_train)
print('梯度下降权重系数为:\n',estimator.coef_) print('梯度下降截距为:\n',estimator.intercept_)
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)}$
批量梯度下降的算法执行过程如下图:

② 随机梯度下降(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正则化
作用:可以使其中一些W的值直接为0,删除这个特征的影响。
LOSSO回归
- 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)$其几何图形是:


抛物面代表的是$\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)
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)
plt.xscale('log') plt.xlabel('Log(Lambda)') plt.ylabel('Cofficients') plt.show()
|
输出结果:

- 正则化力度λ越大,权重系数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)
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_)
|
输出结果:
代码实现
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)
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)
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_)
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)
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_)
|
输出结果:
代码实现
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)
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)
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]

解释:将任意的输入映射到了[0,1]区间,我们在线性回归中可以得到一个预测值,再将该值映射到Sigmoid 函数中这样就完成了由值到概率的转换,也就是分类任务
预测函数:
$$
h_w(x)=g(w^Tx)=\frac{1}{1+e^{-w^Tx}}
$$
分类任务:
$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)=\left{\begin{array}{ll}
-\log \left(h_{\theta}(x)\right) & \text { if } y=1 \
-\log \left(1-h_{\theta}(x)\right) & \text { if } y=0
\end{array}\right.
$$

综合完整损失函数:$$
\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)
默认将类别数量少的当做正例
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
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)
data = data.replace(to_replace='?', value=np.nan) data = data.dropna() print(data.isnull().any())
x = data[column_name[1:10]] y = data[column_name[10]]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test)
lr = LogisticRegression() lr.fit(x_train, y_train)
print("权重:\n", lr.coef_) print("偏置:\n", lr.intercept_)
y_predict=lr.predict(x_test) print('y_predict:\n',y_predict) print('直接比对真实值和预测值:\n',y_test y_predict)
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: [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
| 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)

示例及实现代码
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]
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]]
|

混淆矩阵可视化
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)
|

分类评估报告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)

例:
假设这样一个情况,如果99个样本癌症,1个样本非癌症,不管怎样我全都预测正例(默认癌症为正例),准确率就为99%但是这样效果并不好,这就是样本不均衡下的评估问题
解:准确率:99% 召回率:99/99=100% 精确率:99%
F1—score:2*99%/199%=99.497%
AUC:0.5 —不好的模型 AUC下文介绍
问题:如何衡量样本不均衡下的评估?
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)
- FPR = FP / (FP + FN)
ROC曲线
- ROC曲线的横轴就是FPR,纵轴就是TPR,当二者相等时,表示的意义则是:对于不论真实类别是1还是0的样本,分类器预测为1的概率是相等的,此时AUC为0.5

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_test = np.where(y_test > 2.5, 1, 0) from sklearn.metrics import roc_auc_score print("AUC指标:", roc_auc_score(y_test, lr.predict(x_test)))
y_score = lr.predict_proba(x_test)[:, 1]
from sklearn import metrics fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
roc_auc = metrics.auc(fpr, tpr)
import matplotlib.pyplot as plt 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('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
|

总结
- 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等位置


回归模型的评估
主要有以下方法:
指标 |
描述 |
metrics方法 |
Mean Absolute Error (MAE) |
平均绝对误差 |
from sklearn.metrics import mean_absolute_error |
Mean Square Error(MSE) |
平均方差 |
from sklearn.metrics import mean_squared_error |
R-Squared |
R平方值 |
from sklearn.metrics import r2_score |
代码:
1 2 3 4 5 6 7 8
| 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)
lr.score(X_test,y_test)
|
数学理解: 分母理解为原始数据的离散程度,分子为预测数据和原始数据的误差,二者相除可以消除原始数据离散程度的影响
其实“决定系数”是通过数据的变化来表征一个拟合的好坏。
理论上取值范围$ (-∞,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
线性回归的模型保存加载案例
保存
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
|
model = joblib.load("test.pkl") print("从文件加载进来的模型预测房价的结果:", std_y.inverse_transform(model.predict(x_test)))
|
无监督学习-K-means算法
什么是无监督学习
没有目标值—无监督学习
例:
一家广告平台需要根据相似的人口学特征和购买习惯将美国人口分成不同的小组,以便广告客户可以通过有关联的广告接触到他们的目标客户。
Airbnb 需要将自己的房屋清单分组成不同的社区,以便用户能更轻松地查阅这些清单。
一个数据科学团队需要降低一个大型数据集的维度的数量,以便简化建模和降低文件大小。
我们可以怎样最有用地对其进行归纳和分组?我们可以怎样以一种压缩格式有效地表征数据?这都是无监督学习的目标,之所以称之为无监督,是因为这是从无标签的数据开始学习的。
无监督学习包含算法
K-means原理
我们先来看一下一个K-means的聚类效果图

K-means聚类步骤
1、随机设置K个特征空间内的点作为初始的聚类中心
2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别
3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)
4、如果计算得出的新中心点与原中心点一样,那么结束,否则重新进行第二步过程
K—超参数 根据以下确定: 1)看需求;2)调节超参数
我们以一张图来解释效果

K-means算法API
sklearn.cluster.KMeans(n_clusters=8,init=‘k-means++’)
案例: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
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")
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"])
table = pd.crosstab(tab3["user_id"], tab3["aisle"]) data = table[:10000]
from sklearn.decomposition import PCA
transfer = PCA(n_components=0.95)
data_new = transfer.fit_transform(data) print(data_new.shape)
from sklearn.cluster import KMeans estimator=KMeans(n_clusters=3)
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$ 到本身簇的距离平均值。最终计算出所有的样本点的轮廓系数平均值
轮廓系数值分析

分析过程(我们以一个蓝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
| from sklearn.metrics import silhouette_score print(silhouette_score(data_new,y_predict))
|
输出结果:
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
| import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler
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)
data = data.replace(to_replace='?', value=np.nan) data = data.dropna() print(data.isnull().any())
x = data[column_name[1:10]] y = data[column_name[10]]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test)
from sklearn import svm module = svm.SVC() module.fit(x_train, y_train)
y_predict=module.predict(x_test) print('y_predict:\n',y_predict) print('直接比对真实值和预测值:\n',y_test y_predict)
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_test = np.where(y_test > 2.5, 1, 0) from sklearn.metrics import roc_auc_score print("AUC指标:", roc_auc_score(y_test, module.predict(x_test)))
y_score = module.fit(x_train, y_train).decision_function(x_test)
from sklearn import metrics fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
roc_auc = metrics.auc(fpr, tpr)
import matplotlib.pyplot as plt 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('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
|

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
| import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler
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)
data = data.replace(to_replace='?', value=np.nan) data = data.dropna() print(data.isnull().any())
x = data[column_name[1:10]] y = data[column_name[10]]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
std = StandardScaler() x_train = std.fit_transform(x_train) x_test = std.transform(x_test)
from sklearn.ensemble import GradientBoostingClassifier 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)
y_predict=module.predict(x_test) print('y_predict:\n',y_predict) print('直接比对真实值和预测值:\n',y_test y_predict)
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_test = np.where(y_test > 2.5, 1, 0) from sklearn.metrics import roc_auc_score print("AUC指标:", roc_auc_score(y_test, module.predict(x_test)))
y_score = module.predict_proba(x_test)[:, 1]
from sklearn import metrics fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
roc_auc = metrics.auc(fpr, tpr)
import matplotlib.pyplot as plt 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('1-Specificity') plt.ylabel('Sensitivity') plt.show()
|