一、线性模型基本概念
线性模型不是指某一个模型,而是一类模型。在机器学习领域,常用的线性模型包括,线性回归、岭回归、套索回归、逻辑回归和线性SVC等。
1.线性模型的图形表示——拟合两点
假设有两个点(1,3)和(4,5),用python计算出穿过两点的直线方程,并画出图形。
#求解穿过点的直线方程,并绘图
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression #导入线性回归模型
#输入两点的横坐标
X = [[1], [4]]
#输入两点的纵坐标
y = [3, 5]
#用线性模型拟合这两个点
lr = LinearRegression().fit(X, y)
#画出两个点和直线图形
z = np.linspace(0, 5, 20)
plt.scatter(X, y, s=80)
plt.plot(z, lr.predict(z.reshape(-1, 1), c='k'))
#设定图片标题
plt.title('Straight Line')
#输出直线方程
print('直线方程为:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
plt.show()
执行结果如下,直线穿过两个点:
直线方程为:
==========================
y = 0.667 x + 2.333
注释1:
numpy.linspace 用来生成等差数列
函数原型:numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
参数解释:
start:返回样本数据开始点
stop:返回样本数据结束点
num:生成的样本数据量,默认为50
endpoint:True则包含stop;False则不包含stop
retstep:If True, return (samples, step), where step is the spacing between samples.(即如果为True则结果会给出数据间隔)
dtype:输出数组类型
axis:0(默认)或-1
返回类型:
Return evenly spaced numbers over a specified interval.
(在start和stop之间返回均匀间隔的数据)
Returns num evenly spaced samples, calculated over the interval [start, stop].
(返回的是 [start, stop]之间的均匀分布)
The endpoint of the interval can optionally be excluded.
Changed in version 1.16.0: Non-scalar start and stop are now supported.
(可以选择是否排除间隔的终点)
注释2:
reshape(行,列) 可以根据指定的数值将数据转换为特定的行数和列数,就是转换成矩阵。
如果 reshape(-1,1)或者 reshape(1,-1)意味着转换成为一列或者一行
注释3:
sklearn.linear_model.LogisticRegression
函数原型:sklearn.linear_model.LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, verbose=0, warm_start=False, n_jobs=1)
参数解释:
penalty: 一个字符串,指定了正则化策略。可选 l2 、l1
dual : 一个布尔值。如果为True,则求解对偶形式(只在penalty=‘l2’且solver=‘liblinear’有对偶形式),如果为False,则求解原始形式。
C : 一个浮点数。它指定了罚项系数的倒数。如果它的值越小,则正则化项越大。
fit_intercept : 一个布尔值,指定是否需要计算b值。如果为False,那么不计算b值。
intercept_scaling : 一个浮点数。只有当solver=‘liblinear’才有意义。当采用fit_intercept时,相当于人造了一个特征,该特征恒为1,其权重为b。在计算正则化项的时候,该人造特征也被考虑了。因此为了降低这个人造特征的影响,需要提供intercept_scaling。
class_weight : 一个字典或者字符串‘balanced’。
字典 : 字典给出每个分类的权重。
balanced : 每个分类的权重与该分类在样本集中出现的频率成反比。
未指定 : 每个分类权重都为1。
max_iter : 一个整数,制定最大迭代数。
random_state :一个整数或者一个RandomState实例,或者None。
整数,则指定了随机数生成器的种子。
RandomState,则指定了随机数生成器。
None,则默认使用随机数生成器。
solver : 一个字符串,指定了求解最优化的算法,可以为:
newton-cg : 使用牛顿法。只适用于penalty=‘l2’。
lbfgs : 使用L-BFGS拟牛顿法。只适用于penalty=‘l2’。
liblinear : 使用liblinear,适用于小数据集。
sag : 使用Stochastic Average Gradient Descent算法,适用于大数据集。只适用于penalty=‘l2’。
tol : 一个浮点数,指定判断迭代收敛与否的阈值
multi_class : 一个字符串,指定对于多分类问题的策略,可以为:
ovr : 采用one-vs-rest策略。
multinomial : 直接采用多分类逻辑回归策略,不能与liblinear共存。
verbose : 一个正数。用于开启关闭迭代中输出日志。
warm_start: 一个布尔值。如果为True,那么使用前一次训练结果继续训练。否则从头开始训练
n_jobs : 一个正数。任务并行时指定的CPU数量。如果为-1则使用所有可用的CPU。
返回类型:
coef_ : 权重向量。
intercept_ :b值。
n_iter :实际迭代次数。
2.线性模型的图形表示——拟合三点
再增加一个点(3, 3)再看结果
#求解穿过点的直线方程,并绘图
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression #导入线性回归模型
#输入两点的横坐标
#X = [[1], [4]]
#输入两点的纵坐标
#y = [3, 5]
#输入三点的横坐标
X = [[1], [4], [3]]
#输入三点的纵坐标
y = [3, 5, 3]
#用线性模型拟合输入点
lr = LinearRegression().fit(X, y)
#画出点和直线图形
z = np.linspace(0, 5, 20)
plt.scatter(X, y, s=80)
plt.plot(z, lr.predict(z.reshape(-1, 1)), c='k')
#设定图片标题
plt.title('Straight Line')
#输出直线方程
print('直线方程为:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
plt.show()
执行结果如下,直线未穿过三个点,但是位于一个和3个点距离相加最小的位置:
直线方程为:
==========================
y = 0.571 x + 2.143
3.线性模型的图形表示——拟合多点
使用scikit-learn 生成的 make_regression 数据集
#求解穿过多点的直线方程,并绘图
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression #回归分析数据生成器
from sklearn.linear_model import LinearRegression #导入线性回归模型
#生成用于回归分析的数据集
X, y = make_regression(n_samples=50, n_features=1, n_informative=1, noise=50, random_state=1)
#使用线性模型对数据进行拟合
reg = LinearRegression()
reg.fit(X, y)
#z是生成的等差数列,用来画出模型的预测结果图形
z = np.linspace(-3, 3, 200).reshape(-1, 1)
plt.scatter(X, y, c='b', s=60)
plt.plot(z, reg.predict(z), c='k')
print('直线方程为:')
print('==========================')
print('y = {:.3f}'.format(reg.coef_[0]), 'x',' + {:.3f}'.format(reg.intercept_))
print('直线的斜率为:{:.2f}'.format(reg.coef_[0]))
print('直线的截距为:{:.2f}'.format(reg.intercept_))
plt.show()
执行结果如下:
直线方程为:
==========================
y = 79.525 x + 10.922
直线的斜率为:79.52
直线的截距为:10.92
注释:
sklearn.datasets.make_regression
函数原型:sklearn.datasets.make_regression(_samples=100, n_features=100, n_informative=10,
n_targets=1, bias=0.0, effective_rank=None,
tail_strength=0.5, noise=0.0, shuffle=True, coef=False,
random_state=None)关键参数解释:
n_samples(生成样本数)
n_features(样本特征数)
noise(样本随机噪音)
coef(是否返回回归系数)返回类型:
X为样本特征
y为样本输出
coef为回归系数
二、基本的线性模型——线性回归
线性回归,也称为最小二乘法(OLS)。基于预测值很真实值的均方误差最小化来进行模型求解的方法称为“最小二乘法”。在线性回归中,最小二乘法就是试图找到一条直线,使所有样本到直线上的欧式距离之和最小。线性回归没有可供用户调节的参数。这意味着,模型的复杂度不可控。
使用糖尿病数据集进行演示.
#线性回归
#线性回归
from sklearn.datasets import load_diabetes #载入糖尿病数据
from sklearn.linear_model import LinearRegression #导入线性回归模型
from sklearn.model_selection import train_test_split #切分训练集和测试集
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
lr = LinearRegression().fit(X_train, y_train)
print('代码运行结果为:')
print('==========================')
print('lr.coef_为:{}'.format(lr.coef_))
print('lr.intercept_为:{}'.format(lr.intercept_))
print('\n')
print('回归方程为:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), '*x1 + {:.3f}'.format(lr.coef_[1]), '*x2' ,' + ({})'.format(lr.intercept_))
print('\n')
print('==========================')
print("训练数据得分:{:.2f}".format(lr.score(X_train, y_train)))
print("测试数据得分:{:.2f}".format(lr.score(X_test, y_test)))
执行结果如下:
代码运行结果为:
==========================
lr.coef_为:[ 11.5106203 -282.51347161 534.20455671 401.73142674 -1043.89718398
634.92464089 186.43262636 204.93373199 762.47149733 91.9460394 ]
lr.intercept_为:152.5624877455247
回归方程为:
==========================
y = 11.511 *x1 + -282.513 *x2 + (152.5624877455247)
==========================
训练数据得分:0.53
测试数据得分:0.46
结果显示得分很低,也就是模型在实际数据中效果不好,出现了过拟合现象,因此,需要对线性回归模型就行正则化,使得可以控制模型的复杂度。
2.1、使用L2正则化的线性模型——岭回归
岭回归是一种改良的最小二乘法。可以避免过拟合。在岭回归中,模型会保留所有的特征变量,但是会减小特征变量的系数值,让特征变量对预测结果的影响变小,在岭回归中是通过改变其alpha参数来控制减小特征变量系数的程度。而这种通过保留全部特征变量,只是降低特征变量的系数值来避免过拟合的方法,成为L2正则化。
在岭回归中。是通过linear_model.Ridge函数来调用的。以糖尿病为例,并对比不同alpha值和线性回归模型下,模型的coef_属性值。
from sklearn.linear_model import Ridge #导入岭回归
from sklearn.linear_model import LinearRegression #导入线性回归模型
from sklearn.datasets import load_diabetes #载入糖尿病数据
from sklearn.model_selection import train_test_split #切分训练集和测试集
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
lr = LinearRegression().fit(X_train, y_train)
#取不同的 alpha 来看参数对结果的影响
ridge1 = Ridge(alpha=1).fit(X_train, y_train)
ridge10 = Ridge(alpha=10).fit(X_train, y_train)
ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print('代码运行结果为:')
print('==========================')
print("训练数据得分:{:.2f}".format(ridge10.score(X_train, y_train)))
print("测试数据得分:{:.2f}".format(ridge10.score(X_test, y_test)))
#绘制 线性模型系数
plt.plot(lr.coef_, 'o', label = 'LinearRegression')
#绘制 alpha = 0.1 时的模型系数
plt.plot(ridge01.coef_, 's', label = 'Ridge alpha=0.1')
#绘制 alpha = 1 时的模型系数
plt.plot(ridge1.coef_, '^', label = 'Ridge alpha=1')
#绘制 alpha = 10 时的模型系数
plt.plot(ridge10.coef_, 'v', label = 'Ridge alpha=10')
plt.xlabel("coefficient index 系数序号")
plt.ylabel("coeffient magniutde 系数量级")
plt.hlines(0, 0, len(lr.coef_))
plt.legend()
plt.show()
运行结果为:
图中。横轴为coef_属性,纵轴为特征变量的系数量级。从图中可以看出,当 alpha = 10 时,特征变量系数大多在0附近;当 alpha = 1时,岭回归的特征变量系数明显增大;;当 alpha = 0.1 时,岭回归的特征变量系数更大,甚至于线性回归模型的点重合了。
另外一个理解正则化对模型的影响的方法,就取一个固定的alpha值,然后改变训练集的数据量,得到一个随数据集大小而不断改变的模型评分折线图,具体代码如下:
import numpy as np
from sklearn.linear_model import Ridge #导入岭回归
from sklearn.linear_model import LinearRegression #导入线性回归模型
from sklearn.datasets import load_diabetes #载入糖尿病数据
from sklearn.model_selection import train_test_split #切分训练集和测试集
from sklearn.model_selection import learning_curve,KFold
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
#定义一个绘制折线图的函数
def plot_learning_curve(est, X, y):
training_set_size, train_scores, test_scores = learning_curve(est, X, y, train_sizes=np.linspace(.1, 1, 20),
cv=KFold(20, shuffle=True, random_state=1))
estimator_name = est.__class__.__name__
line = plt.plot(training_set_size, train_scores.mean(axis=1), '--', label="training "+ estimator_name)
plt.plot(training_set_size, test_scores.mean(axis=1), '--', label="test "+ estimator_name, c=line[0].get_color())
plt.xlabel('Trainint set size')
plt.ylabel('Score')
plt.ylim(0, 1.1)
plot_learning_curve(Ridge(alpha=1), X, y)
plot_learning_curve(LinearRegression(), X, y)
plt.legend(loc=(0, 1.05), ncol=2, fontsize=11)
plt.show()
执行结果如下:
从图上可以看出,由于岭回归模型是进过正则化的模型,因此它在整个图像中训练数据及的得分比线性回归的低,但是岭回归的测试数据集得分和训练数据集得分差异小。随着数据集的增加,如果有足够多的数据,那么正则化就没那么重要了,岭回归和线性回归的表现相差无几。
注释1:
sklearn.model_selection.learning_curve
函数原型:sklearn.model_selection.learning_curve(estimator, X, y, groups=None, train_sizes=array([0.1, 0.33, 0.55, 0.78, 1. ]), cv=’warn’, scoring=None, exploit_incremental_learning=False, n_jobs=None, pre_dispatch=’all’, verbose=0, shuffle=False, random_state=None, error_score=’raise-deprecating’)
关键参数解释:
estimator:实现“ fit”和“ predict”方法的对象类型。每次验证都会克隆的该类型的对象。
X:数组类,形状(n_samples,n_features)。训练向量,其中n_samples是样本数,n_features是特征数。
y:数组类,形状(n_samples)或(n_samples,n_features),可选。相对于X的目标进行分类或回归;无监督学习无。
groups:数组类,形状为(n_samples,),可选。将数据集拆分为训练/测试集时使用的样本的标签分组。仅用于连接交叉验证实例组(例如GroupKFold)。
train_sizes:数组类,形状(n_ticks),dtype float或int。训练示例的相对或绝对数量,将用于生成学习曲线。如果dtype为float,则视为训练集最大尺寸的一部分(由所选的验证方法确定),即,它必须在(0,1]之内,否则将被解释为绝对大小注意,为了进行分类,样本的数量通常必须足够大,以包含每个类中的至少一个样本(默认值:np.linspace(0.1,1.0,5))
cv:int,交叉验证生成器或可迭代的,可选的.确定交叉验证拆分策略。cv的可能输入是:
None,要使用默认的三折交叉验证(v0.22版本中将改为五折)
整数,用于指定(分层)KFold中的折叠数,
CV splitter
可迭代的集(训练,测试)拆分为索引数组。
对于整数/无输入,如果估计器是分类器,y是二进制或多类,则使用StratifiedKFold。在所有其他情况下,都使用KFold。
scoring:字符串,可调用或无,可选,默认:None。字符串(参阅model evaluation documentation)或带有签名scorer(estimator, X, y)的计分器可调用对象/函数。
exploit_incremental_learning:布尔值,可选,默认值:False. 如果估算器支持增量学习,此参数将用于加快拟合不同训练集大小的速度。
n_jobs:int或None,可选(默认=None)。要并行运行的作业数。None表示1。 -1表示使用所有处理器。有关更多详细信息,请参见词汇表。
pre_dispatch:整数或字符串,可选。并行执行的预调度作业数(默认为全部)。该选项可以减少分配的内存。该字符串可以是“ 2 * n_jobs”之类的表达式。
verbose:整数,可选。控制详细程度:越高,消息越多。
shuffle:布尔值,可选。是否在基于``train_sizes’'为前缀之前对训练数据进行洗牌。
random_state:int,RandomState实例或无,可选(默认=None)。如果为int,则random_state是随机数生成器使用的种子;否则为false。如果是RandomState实例,则random_state是随机数生成器;如果为None,则随机数生成器是np.random使用的RandomState实例。在shuffle为True时使用。
error_score:‘raise’ | ‘raise-deprecating’ 或数字。如果估算器拟合中出现错误,则分配给分数的值。如果设置为“ raise”,则会引发错误。如果设置为“raise-deprecating”,则会在出现错误之前打印FutureWarning。如果给出数值,则引发FitFailedWarning。此参数不会影响重新安装步骤,这将始终引发错误。默认值为“不赞成使用”,但从0.22版开始,它将更改为np.nan。返回类型:
train_sizes_abs:数组,形状(n_unique_ticks,),dtype int。已用于生成学习曲线的训练示例数。 请注意,ticks的数量可能少于n_ticks,因为重复的条目将被删除。
train_scores:数组,形状(n_ticks,n_cv_folds)。训练集得分。
test_scores:数组,形状(n_ticks,n_cv_folds)。测试集得分。
函数参考:sklearn中的学习曲线learning_curve函数
注释2:
sklearn.model_selection.KFold
函数原型:KFold(n_split, shuffle, random_state)
关键参数解释:
n_split:要划分的折数
shuffle::每次都进行shuffle,测试集中折数的总和就是训练集的个数
random_state:随机状态
2.2、使用L1正则化的线性模型——套索回归
和岭回归一样,套索回归也会 将系数限制在非常接近0 的范围内,但它限制的方式称之为 L1 正则化。与L2 正则化不同的是,L1 正则化会导致在使用套索回归的时候,有一部分特征的系数会正好等于0。也就是说,有一些特征会被模型忽略掉。下面再用糖尿病数据验证套索回归。
import numpy as np
from sklearn.linear_model import Ridge #导入套索回归
from sklearn.linear_model import Lasso #导入岭回归
from sklearn.datasets import load_diabetes #载入糖尿病数据
from sklearn.model_selection import train_test_split #切分训练集和测试集
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
#取不同的 alpha 来看参数对套索回归的影响
lasso01= Lasso(alpha=0.1, max_iter=100000).fit(X_train, y_train)#max_iter迭代次数
lasso1= Lasso(alpha=1, max_iter=100000).fit(X_train, y_train)
lasso00001= Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)
#取不同的 alpha 来看参数对岭回归的影响
ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
#绘制 alpha =1 时的模型系数
plt.plot(lasso1.coef_, 's', label = "Lasso alpha=1")
#绘制 alpha =0.1 时的模型系数
plt.plot(lasso01.coef_, '^', label = "Lasso alpha=0.1")
#绘制 alpha =0.00001 时的模型系数
plt.plot(lasso00001.coef_, 'v', label = "Lasso alpha=0.00001")
#绘制 alpha =0.1 时的模型系数
plt.plot(ridge01.coef_, 'o', label = "Ridge alpha=0.1")
plt.legend(loc=(0, 1.05), ncol=2)
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.show()
执行结果如下图,在alpha=1的时候,不仅大部分系数为0,仅存的几个非零系数也特别小。在alpha=0.1的时候,虽然大部分系数为0,但仅存的几个非零系数比alpha=1的时候的大。在alpha=0.0001的时候,模型几乎没有被正则化。
2.3、L1正则化和L2正则化的对比
在实际应用中,岭回归是两个模型中的优选。但要依据实际情况而定。
数据集中的特征过多,而其中只有一小部分是真正重要的,选L1正则化的模型,如套索回归。
数据集中的特征本来就不多,而且每一个都有重要的作用,选L2正则化的模型,如岭回归。
三、其他线性模型
弹性网模型(Elastic Net):综合了套索回归和岭回归的惩罚因子。实践中,这两个模型的组合效果是组好的,但需要调节2个参数,即L1正则化参数和L2正则化参数。
逻辑斯蒂回归(Logis Regression)
线性支持向量机(Linear SVM)