线性回归
公式: $\hat{y}=\theta_0+\theta_1x_1+\theta_2x_2+…+\theta_nx_n$
向量形式:$\hat{y}=h_\theta(\vec{x})=\vec{\theta_0^T}\cdot \vec{x}$
损失函数:$MSE(\vec{X},h_\theta)=\frac{1}{m}\sum_{i=1}^m(\vec{\theta_0^T}\cdot \vec{x^{(i)}}-y^{(i)})$
通过最小化MSE球的参数$\theta$,可得标准方程:$\hat{\theta}=(X^TX)^{(-1)}X^Ty$
1 2 3 4
| %matplotlib inline import numpy as np from sklearn.linear_model import LinearRegression import matplotlib.pyplot as plt
|
1 2
| X = 2 * np.random.rand(100,1) y = 4 + 3 * X + np.random.randn(100,1)
|
1 2
| lin_reg = LinearRegression() lin_reg.fit(X, y)
|
LinearRegression()
sklearn中线性回归的重要属性和方法
intercept_
表示偏置项
coef_
表示权重
fit(X, y)
表示拟合过程
predict(X, y)
表示预测过程
score(X, y)
对于线性回归表示相关系数
1
| lin_reg.intercept_,lin_reg.coef_
|
(array([3.93410448]), array([[2.94751289]]))
1 2 3 4
| plt.figure() plt.scatter(X, y, c='b', s=2) plt.plot(X, lin_reg.predict(X), color='red') plt.text(1.6,4,'score:{:.2f}'.format(lin_reg.score(X,y)))
|
Text(1.6, 4, 'score:0.80')
梯度下降
中心思想:迭代的调整参数从而使损失函数最小化。
做法:通过测量参数向量$\theta$相关的误差函数和局部梯度,并沿着降低梯度的方向调整,直到梯度为0,到达最小值。
具体来说:首先使用一个随机的$\theta$值,然后逐步改进,每次踏出一步,每一步都尝试降低一点损失函数,直到算法收敛到一个最小值梯度下降中迭代的每一步的步长,叫做学习率,这是个超参数。
如果学习率过高,会导致算法发散,值越来越大;
如果学习率太低,算法需要经过大量迭代才能收敛,这将耗费很长时间。
梯度下降陷阱:在实际情况中,由于算法十分复杂,梯度有可能在未达到全局最小值时就不再下降,收敛到局部最小值在使用梯度下降时最好保证特征值的大小比例都差不多,对数据进行标准化或归一化后再进行训练。
批量梯度下降
要实现梯度下降,需要计算每个模型关于参数$\theta_j$的损失函数的梯度,在计算梯度下降的每一步时,都是基于完整的训练集X的,这就是为什么该算法叫批量梯度下降。但是面对非常庞大的数据集时,算法会变的极慢。但是比标准方程或是SVD快的多。
有了梯度向量,我们就得到了梯度下降的公式,其中$\eta$是学习率:
随机梯度下降
每一步在训练集中随机选择一个实例,并且仅基于该单个实例来计算梯度。
由于算法的随机性质,它比批量随机梯度下降要不规则的多,损失函数不再是缓缓降低直到最小值,而是不断上上下下,但总体来看还是缓慢下降直到收敛到最小值。当成本函数非常不规则时,随机梯度下降可以帮助算法跳出局部最小值。
随机性的好处是可以跳出局部最优,但缺点是永远定位不出最小值。要解决这个困难,一个好办法是逐步降低学习率,确定每个迭代学习率的函数叫做学习率调度。
注意:使用随机梯度下降时,训练实例必须独立且均匀分布,以确保平均而言将参数拉向全局最优,确保该点可以对实例进行随机混洗。
小批量梯度下降
在数据集中,随机取小型批量的实例集计算梯度。
多项式回归
对于非线性的数据我们仍可以用线性模型进行拟合,我们先将每个特征的幂次方添加为一个新特征,然后再训练线性模型。
当存在多个特征时,PolynomialFeatures
可以将特征的所有组合添加到给定的多项式阶数,但要注意特征组合的数量爆炸。
1
| from sklearn.preprocessing import PolynomialFeatures
|
1 2
| X = 6*np.random.rand(100,1)-3 y = 0.5*X**2+X+2+np.random.randn(100,1)
|
1 2 3
| poly = PolynomialFeatures(degree=2,include_bias=False) X_poly = poly.fit_transform(X) X_poly[0]
|
array([-2.82928969, 8.00488013])
1 2 3
| poly_lin_reg = LinearRegression() poly_lin_reg.fit(X_poly, y) poly_lin_reg.intercept_,poly_lin_reg.coef_
|
(array([2.27141448]), array([[0.98932735, 0.41514151]]))
1 2 3 4 5 6
| X_new = np.linspace(-3,3,100).reshape(-1,1) y_new = poly_lin_reg.predict(poly.fit_transform(X_new)) plt.figure() plt.scatter(X, y, c='b',s=2) plt.plot(X_new,y_new,c='r') plt.text(1.6,0,'score:{:.2f}'.format(poly_lin_reg.score(X_poly,y)))
|
Text(1.6, 0, 'score:0.84')
学习曲线
为了避免过拟合,有两种常用的方法:
- 交叉验证:根据交叉验证的指标泛化较差而训练集上很好,说明过拟合;若两者的表现均不理想,则是欠拟合。
- 学习曲线;绘制模型再训练集和验证集上关于训练集大小(或训练迭代)的性能函数。
欠拟合的学习曲线,训练误差和泛化误差都较高且最后都趋于平稳;过拟合时,泛化误差很高,而训练误差也会逐渐趋于平稳,其也较高。
1 2 3
| from sklearn.metrics import mean_squared_error from sklearn.model_selection import train_test_split from sklearn.pipeline import Pipeline
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def my_plot(model,X,y): X_train, X_val, y_train, y_val = train_test_split(X,y,test_size=0.2) train_errors, val_errors = [],[] for m in range(1,len(X_train)): model.fit(X_train[:m], y_train[:m]) y_train_pred = model.predict(X_train[:m]) y_val_pred = model.predict(X_val) train_errors.append(mean_squared_error(y_train[:m],y_train_pred)) val_errors.append(mean_squared_error(y_val,y_val_pred)) plt.plot(np.sqrt(train_errors),c='b',label='train') plt.plot(np.sqrt(val_errors),c='r',label='validation') plt.ylim(0,5) plt.legend() plt.grid(True)
|
1 2 3 4 5
| lin = LinearRegression() poly_lin = Pipeline([ ('poly_feature',PolynomialFeatures(degree=100,include_bias=False)), ('linear',LinearRegression()) ])
|
正则化线性模型
减少过拟合的好方法是对模型进行正则化(约束模型):它拥有的自由度越少,过拟合数据的难度就越大。
岭回归
岭回归也称为Tikhonov正则化,是线性回归的正则化版本,将权重参数$\theta$的L2范数加入损失函数,迫使学习算法不仅拟合数据,还使模型权重尽可能的小。
注意,尽在训练期间将正则化参数添加到损失函数中,训练完成后要使用非正则化的性能度量来评估模型的性能。
在执行岭回归或者其他正则化模型之前,都要对数据特征进行缩放,因为其对数据缩放特征敏感。
岭回归的损失函数:
1
| from sklearn.linear_model import Ridge
|
1 2 3 4 5 6 7 8
| X_ = np.linspace(0,3,100).reshape(-1,1) plt.figure() for alpha in [0,10,100]: ridge = Ridge(alpha=alpha) ridge.fit(X,y) plt.scatter(X,y,c='k',s=4) plt.plot(X_,ridge.predict(X_),label='alpha={}'.format(alpha)) plt.legend()
|
1 2 3 4 5 6 7 8 9 10 11 12
| X_ = np.linspace(0,3,100).reshape(-1,1) plt.figure() for alpha in [0,1e-5,1]: pipe = Pipeline([ ('0',PolynomialFeatures(degree=10,include_bias=False)), ('1',Ridge(alpha=alpha)) ]) pipe.fit(X,y) plt.scatter(X,y,c='k',s=4) plt.plot(X_,pipe.predict(X_),label='alpha={}'.format(alpha)) plt.ylim(0,12) plt.legend()
|
1
| from sklearn.linear_model import SGDRegressor
|
1 2 3 4 5 6 7 8
| plt.figure() for alpha in [0,1e-5,1]: sgd_reg = SGDRegressor(penalty='l2',alpha=alpha) sgd_reg.fit(X,y.ravel()) plt.scatter(X,y,c='k',s=4) plt.plot(X_,sgd_reg.predict(X_),label='alpha={}'.format(sgd_reg.alpha)) plt.ylim(0,12) plt.legend()
|
Lasso回归
线性回归的另一种正则化叫做最小绝对收缩和选择算子回归,简称Lasso回归。他向随时函数添加权重向量的L1范数。
Lasso回归的一个重要特点是,他倾向于完全消除最不重要特征的权重,会自动执行特征选择并输出一个稀疏模型。
其损失函数如下:
为避免在最优解附近反弹,需要逐渐降低训练期间的学习率。
1
| from sklearn.linear_model import Lasso
|
1 2 3 4 5 6 7 8
| plt.figure() for alpha in [0.5,1e-5,1]: lasso_reg = Lasso(alpha=alpha) lasso_reg.fit(X,y) plt.scatter(X,y,c='k',s=4) plt.plot(X_,lasso_reg.predict(X_),label='alpha={}'.format(lasso_reg.alpha)) plt.ylim(0,12) plt.legend()
|
弹性网络
弹性网络是介于岭回归和Lasso回归的中间地带,正则项是权重系数的L1,L2范数的混合,用混合系数r控制。
大多数情况下,我们应避免使用纯线性回归,默认岭回归;担当实际用到的特征数很少时,应倾向于使用Lasso或弹性网络。
弹性网络的损失函数如下
1
| from sklearn.linear_model import ElasticNet
|
1 2 3 4 5 6 7 8
| plt.figure() for alpha in [0.5,1e-5,1]: elatic = ElasticNet(alpha=alpha,l1_ratio=0.5) elatic.fit(X,y) plt.scatter(X,y,c='k',s=4) plt.plot(X_,elatic.predict(X_),label='alpha={},r={}'.format(elatic.alpha,elatic.l1_ratio)) plt.ylim(0,12) plt.legend()
|
逻辑回归
逻辑回归被广泛用于估算一个实例属于某个特定类别的概率,若预估概率超过50%啧判定该例属于该类别,称为正例,记为1;反之则不属于该类别,称为反类,记为0。它的输出是结果的数理逻辑值。
逻辑回归模型的估计概率:
$\hat{p}=h_\theta(\vec{x})=\sigma(\vec{x^T}\vec{\theta})$
逻辑回归预测模型:
$\hat{y}=
\begin{cases}
0& \hat{p}<0.5\\
1& \hat{p}\ge0.5
\end{cases}$
单个训练实例的损失函数:
$c(\theta)=
\begin{cases}
-\log(\hat{p})& y=1\\
-\log(1-\hat{p})& y=0
\end{cases}$
逻辑回归损失函数:
$J(\theta)={1\over m} \sum_{i=1}^m[y^i\log(\hat{p}^i)+(1-y^i)\log(1-\hat{p}^i)]$
1 2
| from sklearn.linear_model import LogisticRegression from sklearn.datasets import load_iris
|
1 2 3
| iris = load_iris() X = iris['data'][:,3:] y = (iris['target']==2).astype(np.int)
|
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
1 2
| log_reg = LogisticRegression() log_reg.fit(X,y)
|
LogisticRegression()
1 2
| X_ = np.linspace(0,3,1000).reshape(-1,1) y_ = log_reg.predict_proba(X_)
|
1 2 3 4 5 6
| plt.figure(figsize=(10,5)) plt.plot(X_,y_[:,0],'g--',label='not virginica') plt.plot(X_,y_[:,1],'b-',label='virginica') plt.legend() plt.plot(X[y==0], y[y==0], "gs") plt.plot(X[y==1], y[y==1], "b^")
|
[<matplotlib.lines.Line2D at 0x1d311467520>]
1
| log_reg.predict([[2.3],[1]])
|
array([1, 0])
1
| log_reg.predict_proba([[2.3]])
|
array([[0.05889014, 0.94110986]])
Softmax回归
逻辑回归经过推广可以支持多个类别,称为softmax回归,或叫做多元逻辑回归。
给定一个实例x,Softmax回归模型首先计算出每个类k的分数,然后对这些分数应用softmax函数,估算出每个类的概率。
Softmax回归分类器一次只能预测一个类(多类一输出),因此他只能与互斥的类一同使用。
损失函数被称为交叉熵,用于衡量一组估算出的类的概率跟目标类的匹配程度。
Softmax函数:
$\hat{p}_k={{\exp(s_k(\vec{x}))} \over {\sum_{j=1}^K\exp(s_j(\vec{x}))}}$
回归分类预测:
$\hat{y}=argmax(\hat{p}_k)$
交叉熵损失函数:
$J(\theta)=-\frac{1}{m}\sum_{i=1}^m\sum_{k=1}^Ky_k^i\log(\hat{p}_k^i)$
1 2
| X = iris['data'][:,(2,3)] y = iris['target']
|
1 2
| soft_reg = LogisticRegression(multi_class='multinomial',solver='lbfgs',C=10) soft_reg.fit(X,y)
|
LogisticRegression(C=10, multi_class='multinomial')
1
| soft_reg.predict([[5,2]])
|
array([2])
1
| soft_reg.predict_proba([[5,2]])
|
array([[6.38014896e-07, 5.74929995e-02, 9.42506362e-01]])
1 2
| x0,x1 = np.meshgrid(np.linspace(0,8,1000).reshape(-1,1),np.linspace(0,3.5,1000).reshape(-1,1)) X_ = np.c_[x0.ravel(),x1.ravel()]
|
1 2
| y_prob = soft_reg.predict_proba(X_) y_pred = soft_reg.predict(X_)
|
1
| z=y_pred.reshape(x0.shape)
|
1 2 3 4 5 6 7
| plt.figure(figsize=(10, 4)) plt.plot(X[y==2, 0], X[y==2, 1], "g^", label="Iris virginica") plt.plot(X[y==1, 0], X[y==1, 1], "bs", label="Iris versicolor") plt.plot(X[y==0, 0], X[y==0, 1], "yo", label="Iris setosa") plt.contour(x0,x1,z) plt.legend() plt.axis([0,8,0,3.5])
|
(0.0, 8.0, 0.0, 3.5)
附录 参数列表
LinearRegression
参数 |
说明 |
normalize |
bool, default=False:如果为True,则在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。 |
n_jobs |
int, default=None:设置用于计算的核心数。 |
属性 |
说明 |
coef_ |
线性回归问题的估计系数。 |
intercept_ |
线性模型中的截距项。 |
ElasticNet
参数 |
说明 |
alpha |
float, default=1.0:乘以惩罚项的常数。 |
l1_ratio |
float, default=0.5:弹性网络的混合系数。 |
max_iter |
int, default=1000:最大迭代次数。 |
tol |
float, default=1e-4:优化的容忍度。 |
warm_start |
bool, default=False:设置为True时,重用前面调用的解决方案来进行初始化,否则,只清除前面的解决方案。 |
normalize |
bool, default=False:如果为True,则在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。 |
n_jobs |
int, default=None:设置用于计算的核心数。 |
属性 |
说明 |
coef_ |
线性回归问题的估计系数。 |
intercept_ |
线性模型中的截距项。 |
Lasso
参数 |
说明 |
normalize |
bool, default=False:如果为True,则在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。 |
alpha |
float, default=1.0:乘以惩罚项的常数。 |
n_jobs |
int, default=None:设置用于计算的核心数。 |
max_iter |
int, default=1000:最大迭代次数。 |
tol |
float, default=1e-4:优化的容忍度。 |
warm_start |
bool, default=False:设置为True时,重用前面调用的解决方案来进行初始化,否则,只清除前面的解决方案。 |
属性 |
说明 |
coef_ |
线性回归问题的估计系数。 |
intercept_ |
线性模型中的截距项。 |
Ridge
参数 |
说明 |
normalize |
bool, default=False:如果为True,则在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。 |
alpha |
float, default=1.0:乘以惩罚项的常数。 |
n_jobs |
int, default=None:设置用于计算的核心数。 |
max_iter |
int, default=1000:最大迭代次数。 |
tol |
float, default=1e-4:优化的容忍度。 |
warm_start |
bool, default=False:设置为True时,重用前面调用的解决方案来进行初始化,否则,只清除前面的解决方案。 |
属性 |
说明 |
coef_ |
线性回归问题的估计系数。 |
intercept_ |
线性模型中的截距项。 |
LogisticRegression
参数 |
说明 |
penalty |
{‘L1’, ‘L2’, ‘elasticnet’, ‘none’}, default=’L2’:用于指定处罚中使用的规范。 |
C |
float, default=1.0:正则强度的倒数;必须为正浮点数。 |
n_jobs |
int, default=None:设置用于计算的核心数。 |
max_iter |
int, default=1000:最大迭代次数。 |
tol |
float, default=1e-4:优化的容忍度。 |
warm_start |
bool, default=False:设置为True时,重用前面调用的解决方案来进行初始化,否则,只清除前面的解决方案。 |
class_weight |
dict or ‘balanced’, default=None:以{class_label: weight}的形式与类别关联的权重。如果没有给出,所有类别的权重都应该是1。 “balanced”模式使用y的值来自动调整为与输入数据中的类频率成反比的权重。 |
multi_class |
{‘auto’, ‘ovr’, ‘multinomial’}, default=’auto’:如果选择的选项是“ ovr”,则每个标签都看做二分类问题。对于“multinomial”,即使数据是二分类的,损失最小是多项式损失拟合整个概率分布。 |
属性 |
说明 |
coef_ |
线性回归问题的估计系数。 |
intercept_ |
线性模型中的截距项。 |
classes_ |
分类器已知的类别标签列表。 |